| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width,initial-scale=1"> |
| <title>SimpleApp :: Apache Isis</title> |
| <link rel="canonical" href="https://isis.apache.org/docs/latest/starters/simpleapp.html"> |
| <meta name="generator" content="Antora 2.2.0"> |
| <link rel="stylesheet" href="../../../_/css/site.css"> |
| <link rel="stylesheet" href="../../../_/css/site-custom.css"> |
| <link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,700,700i|Raleway:300,400,500,700,800|Montserrat:300,400,700" rel="stylesheet"> |
| <link rel="home" href="https://isis.apache.org" title="Apache Isis"> |
| </head> |
| <body class="article"> |
| <header class="header"> |
| <nav class="navbar"> |
| <div class="navbar-brand"> |
| <a class="navbar-item" href="https://isis.apache.org"> |
| <span class="icon"> |
| <img src="../../../_/img/isis-logo-48x48.png"></img> |
| </span> |
| <span>Apache Isis</span> |
| </a> |
| <button class="navbar-burger" data-target="topbar-nav"> |
| <span></span> |
| <span></span> |
| <span></span> |
| </button> |
| </div> |
| <div id="topbar-nav" class="navbar-menu"> |
| <a class="navbar-end"> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Quick Start</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Starter Apps</span> |
| <a class="navbar-item" href="../../../docs/latest/starters/helloworld.html">Hello World</a> |
| <a class="navbar-item" href="../../../docs/latest/starters/simpleapp.html">Simple App</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Demos & Tutorials</span> |
| <a class="navbar-item" href="../../../docs/latest/demo/about.html">Demo App</a> |
| <a class="navbar-item" href="https://danhaywood.gitlab.io/isis-petclinic-tutorial-docs/petclinic/1.16.2/intro.html">Petclinic (tutorial)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Resources</span> |
| <a class="navbar-item" href="../../../docs/latest/resources/cheatsheet.html">Cheatsheet</a> |
| <a class="navbar-item" href="../../../docs/latest/resources/icons.html">Icons</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Guides</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Development</span> |
| <a class="navbar-item" href="../../../setupguide/latest/about.html">Setup Guide</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Core</span> |
| <a class="navbar-item" href="../../../userguide/latest/about.html">User Guide</a> |
| <a class="navbar-item" href="../../../refguide/latest/about.html">Reference Guide</a> |
| <a class="navbar-item" href="../../../testing/latest/about.html">Testing Guide</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Libraries</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">For Use in Apps</span> |
| <a class="navbar-item" href="../../../subdomains/latest/about.html">Subdomain Libraries</a> |
| <a class="navbar-item" href="../../../valuetypes/latest/about.html">Value Types</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Integrate between Apps</span> |
| <a class="navbar-item" href="../../../mappings/latest/about.html">Bounded Context Mapping Libraries</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Other</span> |
| <a class="navbar-item" href="../../../incubator/latest/about.html">Incubator</a> |
| <a class="navbar-item" href="../../../legacy/latest/about.html">Legacy</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Components</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Viewers</span> |
| <a class="navbar-item" href="../../../vw/latest/about.html">Wicket UI</a> |
| <a class="navbar-item" href="../../../vro/latest/about.html">Restful Objects (REST)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Security</span> |
| <a class="navbar-item" href="../../../security/latest/about.html">Security Guide</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Persistence</span> |
| <a class="navbar-item" href="../../../pjdo/latest/about.html">DataNucleus (JDO)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Extensions</span> |
| <a class="navbar-item" href="../../../extensions/latest/about.html">Extensions Catalog</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">Support</a> |
| <div class="navbar-dropdown"> |
| <span class="navbar-item navbar-heading">Contact</span> |
| <a class="navbar-item" href="../../../docs/latest/support/slack-channel.html">Slack</a> |
| <a class="navbar-item" href="../../../docs/latest/support/mailing-list.html">Mailing Lists</a> |
| <a class="navbar-item" href="https://issues.apache.org/jira/browse/ISIS">JIRA</a> |
| <a class="navbar-item" href="https://stackoverflow.com/questions/tagged/isis">Stack Overflow</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Releases</span> |
| <a class="navbar-item" href="../../../docs/latest/downloads/how-to.html">Downloads</a> |
| <a class="navbar-item" href="../../../relnotes/latest/about.html">Release Notes</a> |
| <a class="navbar-item" href="../../../docs/latest/archive/1-x.html">Archive (1.x)</a> |
| <hr class="navbar-divider"/> |
| <span class="navbar-item navbar-heading">Framework</span> |
| <a class="navbar-item" href="../../../conguide/latest/about.html">Contributors' Guide</a> |
| <a class="navbar-item" href="../../../comguide/latest/about.html">Committers' Guide</a> |
| <a class="navbar-item" href="../../../core/latest/about.html">Core Design</a> |
| </div> |
| </div> |
| <div class="navbar-item has-dropdown is-hoverable"> |
| <a class="navbar-link" href="#">ASF</a> |
| <div class="navbar-dropdown"> |
| <a class="navbar-item" href="http://www.apache.org/">Apache Homepage</a> |
| <a class="navbar-item" href="https://www.apache.org/events/current-event">Events</a> |
| <a class="navbar-item" href="https://www.apache.org/licenses/">Licenses</a> |
| <a class="navbar-item" href="https://www.apache.org/security/">Security</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a> |
| <a class="navbar-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a> |
| <hr class="navbar-divider"/> |
| <a class="navbar-item" href="https://whimsy.apache.org/board/minutes/Isis.html">PMC board minutes</a> |
| </div> |
| </div> |
| <a class="navbar-item" href="../../../docs/latest/about.html"> |
| <span class="icon"> |
| <img src="../../../_/img/home.png"></img> |
| </span> |
| </a> |
| </div> |
| </div> |
| </nav> |
| </header> |
| <div class="body "> |
| <div class="nav-container" data-component="docs" data-version="2.0.0-M3"> |
| <aside class="nav"> |
| <div class="panels"> |
| <div class="nav-panel-pagination"> |
| <a class="page-previous disabled" rel="prev" href="" title=""><span></span></a> |
| <a class="page-next disabled" rel="next" |
| href="" title=""><span></span></a> |
| <!-- |
| page.parent doesn't seem to be set... |
| <a class="page-parent disabled" rel="prev" href="" title=""><span></span></a> |
| --> |
| </div> |
| <div class="nav-panel-menu is-active" data-panel="menu"> |
| <nav class="nav-menu"> |
| <h3 class="title"><a href="../about.html"> </a></h3> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">What is Apache Isis?</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../what-is-apache-isis/isis-in-pictures.html">Apache Isis in pictures</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../what-is-apache-isis/common-use-cases.html">Common Use Cases</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../what-is-apache-isis/screencasts.html">Screencasts</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Quick Start</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/starters/helloworld.html">HelloWorld</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/starters/simpleapp.html">SimpleApp</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/parent-pom/about.html">Parent POM</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/mavendeps/about.html">Aggregator POMs</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Demos & Tutorials</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/demo/about.html">Demo App</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="https://danhaywood.gitlab.io/isis-petclinic-tutorial-docs/petclinic/1.16.2/intro.html">Petclinic (tutorial)</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Resources</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/resources/cheatsheet.html">Cheat Sheet</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/resources/icons.html">Icons</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Guides</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Development</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../setupguide/latest/about.html">Setup Guide</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Core</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../userguide/latest/about.html">User Guide</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../refguide/latest/about.html">Reference Guide</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../testing/latest/about.html">Testing Guide</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Libraries</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">For Use in Apps</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../subdomains/latest/about.html">Subdomain Libraries</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../valuetypes/latest/about.html">Value Types</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Integrate between Apps</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../mappings/latest/about.html">Bounded Context Mapping Libraries</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Other</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../incubator/latest/about.html">Incubator</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../legacy/latest/about.html">Legacy</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Components</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Viewers</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../vw/latest/about.html">Wicket UI</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../vro/latest/about.html">Restful Objects (REST API)</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Security</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../security/latest/about.html">Security Guide</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Persistence</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../pjdo/latest/about.html">DataNucleus (JDO)</a> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Extensions</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="../../../extensions/latest/about.html">Extensions Catalog</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Support</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/support/slack-channel.html">Slack</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/support/mailing-list.html">Mailing Lists</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="https://issues.apache.org/jira/secure/RapidBoard.jspa?rapidView=87">ASF JIRA</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="http://stackoverflow.com/questions/tagged/isis">Stack Overflow</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Releases</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../latest/downloads/how-to.html">Downloads</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../relnotes/latest/about.html">Release Notes</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Nightly Builds (not ASF)</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="https://github.com/apache-isis-committers/isis-nightly">CI</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="https://repo.incode.cloud/">Maven Repo</a> |
| </li> |
| <li class="nav-item" data-depth="3"> |
| <a class="nav-link" href="https://apache-isis-committers.github.io/isis-nightly">Website preview</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| <li class="nav-item" data-depth="0"> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="1"> |
| <button class="nav-item-toggle"></button> |
| <span class="nav-text">Framework</span> |
| <ul class="nav-list"> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../conguide/latest/about.html">Contributors' Guide</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../comguide/latest/about.html">Committers' Guide</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../../../core/latest/about.html">Core Design</a> |
| </li> |
| <li class="nav-item" data-depth="2"> |
| <a class="nav-link" href="../more-thanks/more-thanks.html">Acknowledgements</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </nav> |
| </div> |
| <div class="nav-panel-explore" data-panel="explore"> |
| <div class="context"> |
| <span class="title"> </span> |
| <span class="version">2.0.0-M3</span> |
| </div> |
| <ul class="components"> |
| <li class="component is-current"> |
| <span class="title"> </span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../latest/about.html">latest</a> |
| </li> |
| <li class="version is-current"> |
| <a href="../about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">BC Mappings Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../mappings/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../mappings/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Committers' Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../comguide/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../comguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Contributors' Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../conguide/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../conguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Core Framework</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../core/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../core/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Extensions Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../extensions/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../extensions/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Incubator Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../incubator/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../incubator/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">JDO/DataNucleus</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../pjdo/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../pjdo/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Legacy Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../legacy/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../legacy/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Reference Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../refguide/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../refguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Release Notes</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../relnotes/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../relnotes/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Restful Objects Viewer</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../vro/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../vro/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Security Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../security/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../security/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Setup Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../setupguide/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../setupguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Subdomains Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../subdomains/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../subdomains/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Testing Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../testing/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../testing/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">User Guide</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../userguide/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../userguide/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Value Types Catalog</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../valuetypes/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../valuetypes/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| <li class="component"> |
| <span class="title">Wicket Viewer</span> |
| <ul class="versions"> |
| <li class="version is-latest"> |
| <a href="../../../vw/latest/about.html">latest</a> |
| </li> |
| <li class="version"> |
| <a href="../../../vw/2.0.0-M3/about.html">2.0.0-M3</a> |
| </li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </aside> |
| </div> |
| <main role="main"> |
| <div class="toolbar" role="navigation"> |
| <button class="nav-toggle"></button> |
| <a href="../../latest/about.html" class="home-link"></a> |
| <nav class="breadcrumbs" aria-label="breadcrumbs"> |
| <ul> |
| <li><a href="../about.html"> </a></li> |
| <li><a href="simpleapp.html">SimpleApp</a></li> |
| </ul> |
| </nav> |
| <div class="page-versions"> |
| <button class="version-menu-toggle" title="Show other versions of page">2.0.0-M3</button> |
| <div class="version-menu"> |
| <a class="version" href="../../latest/starters/simpleapp.html">latest</a> |
| <a class="version is-current" href="simpleapp.html">2.0.0-M3</a> |
| </div> |
| </div> |
| <div class="edit-this-page"><a href="https://github.com/apache/isis/blob/docs/isis-2.0.0-M3/starters/adoc/modules/starters/pages/simpleapp.adoc">Edit</a></div> |
| </div> |
| <article class="doc"> |
| <a name="section-top"></a> |
| <h1 class="page">SimpleApp</h1> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The quickest way to get started building an application "for real" is to use the <code>simpleapp</code> starter app.</p> |
| </div> |
| <div class="paragraph"> |
| <p>As with the <a href="../../latest/starters/helloworld.html" class="page">HelloWorld</a> starter app, this will download a very simple one-class domain model, namely the <code>SimpleObject</code> entity and a supporting <code>SimpleObjects</code> domain service.</p> |
| </div> |
| <div class="paragraph"> |
| <p>However, the app also provides more structure to assist you as your application grows, with multiple Maven modules, and examples of unit tests, integration tests and BDD (cucumber) specs.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="prerequisites"><a class="anchor" href="#prerequisites"></a>Prerequisites</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Apache Isis is a Java based framework, so in terms of prerequisites, you’ll need to install:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>an LTS version of Java: either Java 8 JDK or Java 11 JDK</p> |
| </li> |
| <li> |
| <p><a href="http://maven.apache.org">Apache Maven</a> 3.5+</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>You’ll probably also want to use an IDE; the Apache Isis committers use either IntelliJ or Eclipse; in the <a href="../../../setupguide/latest/about.html" class="page">Setup Guide</a> 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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="downloading-running"><a class="anchor" href="#downloading-running"></a>Downloading & Running</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Create a new directory, and <code>cd</code> into that directory.</p> |
| </div> |
| <div class="paragraph"> |
| <p>To build the app from the latest stable release, then run the following command:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">curl https://codeload.github.com/apache/isis-app-simpleapp/zip/master | jar xv |
| cd isis-app-simpleapp-master |
| |
| mvn clean install |
| mvn -pl webapp spring-boot:run</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This should only take a few seconds to download, compile and run. |
| Then browse to <a href="http://localhost:8080" class="bare">http://localhost:8080</a>, and read on.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="using-the-app"><a class="anchor" href="#using-the-app"></a>Using the App</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>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 <a href="../../../vw/latest/about.html" class="page">Wicket viewer</a> or use Swagger to access the <a href="../../../vro/latest/about.html" class="page">Restful Objects viewer</a>:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/010-root-page.png"><img src="_images/simpleapp/using/010-root-page.png" alt="010 root page" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Choose the generic Wicket UI, and navigate to the login page:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/020-login-to-wicket-viewer.png"><img src="_images/simpleapp/using/020-login-to-wicket-viewer.png" alt="020 login to wicket viewer" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The app itself is configured to run using <a href="../../../security/latest/about.html" class="page">shiro security</a>, as configured in the <code>WEB-INF/shiro.ini</code> config file. |
| You can login with:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>username: <em>sven</em></p> |
| </li> |
| <li> |
| <p>password: <em>pass</em></p> |
| </li> |
| </ul> |
| </div> |
| <div class="sect2"> |
| <h3 id="wicket-viewer"><a class="anchor" href="#wicket-viewer"></a>Wicket viewer</h3> |
| <div class="paragraph"> |
| <p>Once you’ve logged in you’ll see the default home page:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/030-home-page.png"><img src="_images/simpleapp/using/030-home-page.png" alt="030 home page" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This is a view model annotated with <a href="../../../refguide/latest/applib-ant/HomePage.html" class="page">@HomePage</a>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">HomePageViewModel.java</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@DomainObject( |
| nature = Nature.VIEW_MODEL, |
| objectType = "domainapp.HomePageViewModel" |
| ) |
| @HomePage |
| public class HomePageViewModel { |
| |
| public TranslatableString title() { |
| return TranslatableString.tr("{num} objects", "num", getObjects().size()); |
| } |
| |
| public List<SimpleObject> getObjects() { |
| return simpleObjects.listAll(); |
| } |
| |
| @Inject SimpleObjects simpleObjects; |
| }</code></pre> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="fixtures"><a class="anchor" href="#fixtures"></a>Fixtures</h4> |
| <div class="paragraph"> |
| <p>When prototyping against an in-memory database, it’s useful to have a mechanism to create some initial state. |
| This can be done using fixture scripts, accessible from the <span class="menuseq"><b class="menu">Prototyping</b> <i class="fa fa-angle-right caret"></i> <b class="menuitem">Run Fixture Script</b></span>:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/032-run-fixture-script-prompt.png"><img src="_images/simpleapp/using/032-run-fixture-script-prompt.png" alt="032 run fixture script prompt" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This brings up a dialog to select the fixture script:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/033-run-fixture-script-prompt.png"><img src="_images/simpleapp/using/033-run-fixture-script-prompt.png" alt="033 run fixture script prompt" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The "Domain App Demo" in the drop-down refers to this code:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">DomainAppDemo.java</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public class DomainAppDemo extends FixtureScript { |
| |
| @Override |
| protected void execute(final ExecutionContext ec) { |
| ec.executeChild(this, new TeardownFixtureAbstract2() { |
| @Override |
| protected void execute(final ExecutionContext executionContext) { |
| deleteFrom(SimpleObject.class); |
| } |
| }); |
| ec.executeChild(this, new SimpleObject_persona.PersistAll()); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When executed, all objects created by the fixture are listed:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/034-run-fixture-script-result.png"><img src="_images/simpleapp/using/034-run-fixture-script-result.png" alt="034 run fixture script result" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Navigating back to the home page shows the newly created objects:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/036-home-page-after-fixture-scriptpng.png"><img src="_images/simpleapp/using/036-home-page-after-fixture-scriptpng.png" alt="036 home page after fixture scriptpng" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>As well as running in fixtures from the UI, you can also specify a configuration property to run a fixture script as part of the application start-up:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">config/application.properties</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini"># isis.testing.fixtures.initial-script = \ |
| # domainapp.webapp.application.fixture.scenarios.DomainAppDemo</code></pre> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="create-an-object"><a class="anchor" href="#create-an-object"></a>Create an object</h4> |
| <div class="paragraph"> |
| <p>You can also of course create new objects:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/040-create-object-from-menu.png"><img src="_images/simpleapp/using/040-create-object-from-menu.png" alt="040 create object from menu" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>To avoid obscuring the current page, this is configured to bring up a sidebar dialog:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/050-create-object-from-menu-prompt.png"><img src="_images/simpleapp/using/050-create-object-from-menu-prompt.png" alt="050 create object from menu prompt" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Hitting OK returns the created object:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/060-created-object.png"><img src="_images/simpleapp/using/060-created-object.png" alt="060 created object" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above functionality is implemented by this code:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public static class CreateActionDomainEvent extends ActionDomainEvent {} |
| @Action(semantics = SemanticsOf.NON_IDEMPOTENT, |
| domainEvent = CreateActionDomainEvent.class) <i class="conum" data-value="1"></i><b>(1)</b> |
| @ActionLayout(promptStyle = PromptStyle.DIALOG_SIDEBAR) <i class="conum" data-value="2"></i><b>(2)</b> |
| public SimpleObject create( |
| @Name final String name) { <i class="conum" data-value="3"></i><b>(3)</b> |
| return repositoryService.persist(SimpleObject.ofName(name)); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Published on an in-memory event bus; this allows subscribers to veto or to react to the action invocation.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Policies such as modal or sidebar can be specified per action, or globally in <code>application.yml</code> file.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>The <code>@Name</code> annotation is actually a meta-annotation, meaning that a number of additional semantics (length, layout, validation etc.) are inferred.</td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="invoke-an-action"><a class="anchor" href="#invoke-an-action"></a>Invoke an action</h4> |
| <div class="paragraph"> |
| <p>The <code>SimpleObject</code> contains a couple of properties, and a single action to update that property.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>name</code> property is read-only, and can only be modified using the <code>updateName</code> action:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/070-update-name.png"><img src="_images/simpleapp/using/070-update-name.png" alt="070 update name" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above functionality is implemented by this code:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public static class UpdateNameActionDomainEvent |
| extends SimpleObject.ActionDomainEvent {} |
| @Action(semantics = IDEMPOTENT, |
| publishing = Publishing.ENABLED, <i class="conum" data-value="1"></i><b>(1)</b> |
| associateWith = "name", |
| domainEvent = UpdateNameActionDomainEvent.class) |
| public SimpleObject updateName( |
| @Name final String name) { |
| setName(name); |
| return this; |
| } |
| public String default0UpdateName() { |
| return getName(); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Publishing enabled means that the action invocation is converted into XML and dispatched to all configured implementations of the <a href="../../../refguide/latest/applib-svc/PublisherService.html" class="page">PublisherService</a> SPI. |
| <div class="paragraph"> |
| <p>The framework provides a default implementation that just logs the interaction:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/075-publish-logging-1.png"><img src="_images/simpleapp/using/075-publish-logging-1.png" alt="075 publish logging 1" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>It also logs the fact that the object itself was modified:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/076-publish-logging-2.png"><img src="_images/simpleapp/using/076-publish-logging-2.png" alt="076 publish logging 2" width="600px"></a> |
| </div> |
| </div></td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="edit-a-property"><a class="anchor" href="#edit-a-property"></a>Edit a property</h4> |
| <div class="paragraph"> |
| <p>The <code>notes</code> property is editable, and can be edited in-place. |
| For example:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/080-edit-notes.png"><img src="_images/simpleapp/using/080-edit-notes.png" alt="080 edit notes" width="600px"></a> |
| </div> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="actions-requiring-confirmations"><a class="anchor" href="#actions-requiring-confirmations"></a>Actions requiring confirmations</h4> |
| <div class="paragraph"> |
| <p>It’s also possible to delete an object:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/090-delete-object.png"><img src="_images/simpleapp/using/090-delete-object.png" alt="090 delete object" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The viewer displays a message confirming that the object has been deleted:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/100-object-deleted.png"><img src="_images/simpleapp/using/100-object-deleted.png" alt="100 object deleted" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The above functionality is implemented by this code:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">public static class DeleteActionDomainEvent |
| extends SimpleObject.ActionDomainEvent {} |
| @Action(semantics = NON_IDEMPOTENT_ARE_YOU_SURE, |
| domainEvent = DeleteActionDomainEvent.class) |
| public void delete() { |
| final String title = titleService.titleOf(this); <i class="conum" data-value="1"></i><b>(1)</b> |
| messageService.informUser(String.format("'%s' deleted", title)); |
| repositoryService.removeAndFlush(this); |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Note that this method uses three services provided by the framework; these are injected into the domain object automatically.</td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="swagger-restful-objects"><a class="anchor" href="#swagger-restful-objects"></a>Swagger (Restful Objects)</h3> |
| <div class="paragraph"> |
| <p>Using <span class="menuseq"><b class="menu">Prototyping</b> <i class="fa fa-angle-right caret"></i> <b class="menuitem">Open Swagger UI</b></span> menu item (or just going back to the home page at <a href="http://localhost:8080">localhost:8080</a>) we can use <a href="https://swagger.io/">Swagger UI</a> as a front-end to the REST API provided by the Restful Objects viewer.</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/200-swagger-ui-before-reload.png"><img src="_images/simpleapp/using/200-swagger-ui-before-reload.png" alt="200 swagger ui before reload" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>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:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/210-simpleapp-resources.png"><img src="_images/simpleapp/using/210-simpleapp-resources.png" alt="210 simpleapp resources" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>For example, an object can be created using the resource that represents the <code>SimpleObjects#create</code> action:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/220-create-object-thru-rest-api.png"><img src="_images/simpleapp/using/220-create-object-thru-rest-api.png" alt="220 create object thru rest api" width="600px"></a> |
| </div> |
| </div> |
| <div class="admonitionblock caution"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-caution" title="Caution"></i> |
| </td> |
| <td class="content"> |
| if invoking the action returns a 401 (unauthorised), then navigate to the REST API directly (<a href="http://localhost:8080/restful" class="bare">http://localhost:8080/restful</a> to authenticate the browser first]). |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>The response indicates that the object was successfully created:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/230-create-object-thru-rest-api-response.png"><img src="_images/simpleapp/using/230-create-object-thru-rest-api-response.png" alt="230 create object thru rest api response" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The Swagger UI also provides a resource to retrieve any object:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/240-retrieve-object-using-rest-api.png"><img src="_images/simpleapp/using/240-retrieve-object-using-rest-api.png" alt="240 retrieve object using rest api" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>This results in a representation of the domain object (as per the requested <code>Response Content Type</code>, ie <code>ACCEPT</code> header):</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/using/250-retrieve-object-using-rest-api-response.png"><img src="_images/simpleapp/using/250-retrieve-object-using-rest-api-response.png" alt="250 retrieve object using rest api response" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>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 <a href="http://www.restfulobjects.org">Restful Object spec</a>.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="structure-of-the-app"><a class="anchor" href="#structure-of-the-app"></a>Structure of the App</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The simpleapp starter app is a multi-module project, structured so that you easily extend it as your application grows.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="application-modules"><a class="anchor" href="#application-modules"></a>Application Modules</h3> |
| <div class="paragraph"> |
| <p>The application consists of three modules, with a top-level module acting as an aggregator, the <code>module-simple</code> module that contains the business logic, and <code>webapp</code> module that acts as a bootstrapper.</p> |
| </div> |
| <div class="imageblock plantuml"> |
| <div class="content"> |
| <img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuOekJqrAB2Y8LR2noKqiIyrJoCrFASr9jRFZYeQmT8ipSmjoKcCLC5KWDElfsYcWgUToICrB0Te00000" alt="diagram"> |
| </div> |
| <div class="title">Figure 1. simpleapp module dependencies</div> |
| </div> |
| <div class="paragraph"> |
| <p>Each Maven module contains exactly one <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html">@Configuration</a> class, residing at the package root for that Maven module. |
| So, the <code>module-simple</code> maven |
| The location of this class is used for classpath scanning.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In a larger application there would likely be many more modules containing these domain object modules. |
| For example, you might have a <code>module-customer</code> holding a <code>Customer</code> entity and related entities/services, a <code>module-product</code> holding a <code>Product</code> catalog, and a <code>module-order</code> to hold the <code>Order</code>s placed by <code>Customer</code>s:</p> |
| </div> |
| <div class="imageblock plantuml"> |
| <div class="content"> |
| <img src="http://www.plantuml.com/plantuml/png/SoWkIImgAStDuOekJqrAB2Y8LR2noKqiIyrJoCrFASr9jRFZYeQmTFEBKbABOXLmAqWkBIx9pyMlfg08I2UNO5E2S8AUhfq2ggteZa1M0RSMdoAOlLmEgNafGFy20000" alt="diagram"> |
| </div> |
| <div class="title">Figure 2. Typical application dependencies</div> |
| </div> |
| <div class="paragraph"> |
| <p>We can use Maven dependency management to ensure that there are no cyclic dependencies (order "knows about" product but product does not know about orders) and ensure that the codebase remains decoupled. |
| If Java9 modules become commonplace, we’ll also be able to restrict visibility of classes between modules.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="bootstrapping-framework-modules"><a class="anchor" href="#bootstrapping-framework-modules"></a>Bootstrapping & Framework Modules</h3> |
| <div class="paragraph"> |
| <p>One of the main responsibilities of Spring Boot is - naturally enough - to bootstrap the application. |
| For the webapp, this is done using a class annotated with <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html">@SpringBootApplication</a>. |
| For integration tests, this uses the <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html">@SpringBootTest</a> annotation.</p> |
| </div> |
| <div class="paragraph"> |
| <p>These two different annotations reference a (class annotated with) <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html">@Configuration</a>, which in turn can <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Import.html">@Import</a> other annotations.</p> |
| </div> |
| <div class="paragraph"> |
| <p>By convention, the top-level <code>@Configuration</code> in an Apache Isis application is called the "app manifest". |
| This references not only the application-level modules (described <a href="about.html#application-modules" class="page">above</a>), but also the framework’s modules. |
| There will be several of these app manifests, typically one for the webapp itself, and one for integration testing each module.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <a href="_attachments/simpleapp-modules-dependencies.pptx">diagram</a> below shows how classes fit together:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/simpleapp-modules-dependencies.png"><img src="_images/simpleapp/simpleapp-modules-dependencies.png" alt="simpleapp modules dependencies" width="800px"></a> |
| </div> |
| <div class="title">Figure 3. Module Dependencies</div> |
| </div> |
| <div class="paragraph"> |
| <p>Let’s now review the contents of each of the modules in the simpleapp starter app.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="module-simples-srcmainjava"><a class="anchor" href="#module-simples-srcmainjava"></a>module-simple’s src/main/java</h3> |
| <div class="paragraph"> |
| <p>Under <code>src/main/java</code> we have:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/main/java/ |
| domainapp/ <i class="conum" data-value="1"></i><b>(1)</b> |
| modules/ |
| simple/ <i class="conum" data-value="2"></i><b>(2)</b> |
| dom/ <i class="conum" data-value="3"></i><b>(3)</b> |
| so/ <i class="conum" data-value="4"></i><b>(4)</b> |
| SimpleObject.java |
| SimpleObject.layout.xml |
| SimpleObject.png |
| SimpleObjects.java |
| fixture/ <i class="conum" data-value="5"></i><b>(5)</b> |
| SimpleObject_persona.java |
| SimpleObjectBuilder.java |
| types/ <i class="conum" data-value="6"></i><b>(6)</b> |
| Name.java |
| Notes.java |
| SimpleModule.java <i class="conum" data-value="7"></i><b>(7)</b> |
| META-INF/ |
| persistence.xml <i class="conum" data-value="8"></i><b>(8)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>For simplicity, all the Java source files reside in a <code>domainapp</code> top-level package. |
| Change as required.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Defines the 'simple' module. |
| Apache Isis can be used for both microservice and monolithic architectures, but for the latter it encourages "modular monoliths" from the start.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>The <code>dom</code> package holds the "domain object model" for this module. |
| Modules may have other packages, common ones include <code>types</code> and <code>fixture</code>s (as below), also <code>api</code>s, <code>contribution</code>s, <code>spi</code>s</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>Holds classes for the <code>so</code> ("simple object") entity/aggregate, consisting of the entity definition itself (<code>SimpleObject</code>) and a corresponding repository (<code>SimpleObjects</code>). |
| The associated <code>.layout.xml</code> and <code>.png</code> are optional but provide metadata/resources for rendering (Maven is configured to also treat <code>src/main/java</code> as a resource location).</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="5"></i><b>5</b></td> |
| <td>The <code>fixture</code> package contains classes to set up the database to an initial state (as described <a href="#fixtures">earlier</a>. |
| One of the classes is a <code>FixtureScript</code> (defines <em>how</em> to set up the data) the other is a persona enum (defines <em>what</em> data to set up).</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="6"></i><b>6</b></td> |
| <td>The <code>types</code> package contains meta-annotations to describe the usage of common value types such as <code>String</code>s.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="7"></i><b>7</b></td> |
| <td><code>SimpleModule</code> is a Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html">@Configuration</a> which allows the domain services and entities of the module to be located.<br> |
| This is discussed in more detail below.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="8"></i><b>8</b></td> |
| <td>The <code>persistence.xml</code> file is required when using the JDO/DataNucleus object store (though it is basically boilerplate, an empty file).</td> |
| </tr> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="simplemodule"><a class="anchor" href="#simplemodule"></a>SimpleModule</h4> |
| <div class="paragraph"> |
| <p>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 <code>SimpleModule</code>, it consists of:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">SimpleModule.java</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">package domainapp.modules.simple; |
| ... imports omitted ... |
| @Configuration |
| @Import({}) <i class="conum" data-value="1"></i><b>(1)</b> |
| @ComponentScan <i class="conum" data-value="2"></i><b>(2)</b> |
| public class SimpleModule |
| implements ModuleWithFixtures { <i class="conum" data-value="3"></i><b>(3)</b> |
| |
| @Override |
| public FixtureScript getTeardownFixture() { |
| return new TeardownFixtureAbstract2() { |
| @Override |
| protected void execute(ExecutionContext executionContext) { |
| deleteFrom(SimpleObject.class); |
| } |
| }; |
| } |
| |
| public static class PropertyDomainEvent<S,T> <i class="conum" data-value="4"></i><b>(4)</b> |
| extends org.apache.isis.applib.events.domain.PropertyDomainEvent<S,T> {} |
| |
| public static class CollectionDomainEvent<S,T> |
| extends org.apache.isis.applib.events.domain.CollectionDomainEvent<S,T> {} |
| |
| public static class ActionDomainEvent<S> extends |
| org.apache.isis.applib.events.domain.ActionDomainEvent<S> {} |
| |
| @ConfigurationProperties("app.simple-module") <i class="conum" data-value="5"></i><b>(5)</b> |
| @Data |
| @Validated |
| public static class Configuration { |
| private final Types types = new Types(); |
| @Data |
| public static class Types { |
| private final Name name = new Name(); |
| @Data |
| public static class Name { |
| private final Validation validation = new Validation(); |
| @Data |
| public static class Validation { |
| private char[] prohibitedCharacters = "!&%$".toCharArray(); |
| private String message = "Character '{}' is not allowed"; |
| } |
| } |
| } |
| } |
| |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>This module has no dependencies. |
| If there were, these would be expressed in terms of module classes (each being a Spring <code>@Configuration</code>)</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>specifies this class' package as a root to scan for Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html">@Component</a>s.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>Optionally, modules can implement the testing’s <code>ModuleWithFixtures</code> interface. |
| Through this, they can provide a fixture script which can be used to teardown all entities that are "owned" by the module. |
| Since the module dependency graph is known, this allows all data to be removed, useful for prototyping and sometimes for integration tests.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>The actions for the domain objects and domain services all emit domain events, ultimately inheriting from <a href="#refguide:applib-cm:classes/domainevent/ActionDomainEvent.adoc" class="page unresolved">ActionDomainEvent</a>. |
| By convention, this inheritance hierarchy includes classes defined at the module level. |
| This then allows subscribes to subscribe to all actions emitted by anything within the module.<br> |
| Events can also be emitted for <a href="#refguide:applib-cm:classes/domainevent/PropertyDomainEvent.adoc" class="page unresolved">properties</a> and <a href="#refguide:applib-cm:classes/domainevent/CollectionDomainEvent.adoc" class="page unresolved">collections</a>.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="5"></i><b>5</b></td> |
| <td>Spring Boot <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-typesafe-configuration-properties">type-safe configuration</a>, as per <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/context/properties/ConfigurationProperties.html">@ConfigurationProperties</a> annotation. |
| This Spring Boot feature is used by the framework, but can equally easily be used by application code. |
| The <code>@Name.Specification</code> class uses this configuration property.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>The scanning mechanism is leveraged by Apache Isis to pick up three types of classes:</p> |
| </div> |
| <div class="paragraph"> |
| <p>This will pick up the <code>SimpleObjects</code> repository because it is annotated with the framework’s <a href="../../../refguide/latest/applib-ant/DomainService.html" class="page">@DomainService</a> annotation; itself meta-annotated with <code>@Component</code>.</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>all domain services</p> |
| <div class="paragraph"> |
| <p>These are classes that are annotated with the framework’s <a href="../../../refguide/latest/applib-ant/DomainService.html" class="page">@DomainService</a> annotation. |
| Because <code>@DomainService</code> is meta-annotated as a <code>@Component</code>, these are found automatically and are managed by Spring (ie instantiated, injected etc).</p> |
| </div> |
| <div class="paragraph"> |
| <p>Depending on their nature, domain services are used to build up the menu, or are available to call programmatically, eg repositories, or sometimes both.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the simpleapp starter app, the only domain service is <code>SimpleObjects</code>. |
| This appears in the menu, and also acts as a repository for the <code>SimpleObject</code> entity.</p> |
| </div> |
| </li> |
| <li> |
| <p>all entities.</p> |
| <div class="paragraph"> |
| <p>These are entities that are annotated with both <a href="../../../refguide/latest/applib-ant/DomainObject.html" class="page"><code>@DomainObject</code></a> annotation and with <code>@javax.jdo.annotations.PersistenceCapable</code>. |
| Because <code>@DomainObject</code> is meta-annotated as a <code>@Component</code>, 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.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In the simpleapp starter app, the only entity is <code>SimpleObject</code>.</p> |
| </div> |
| </li> |
| <li> |
| <p>all fixture scripts</p> |
| <div class="paragraph"> |
| <p>These are classes that extend from the testing applib’s <code>FixtureScript</code> class, and are used to setup the database when running in prototype mode (against an in-memory database).</p> |
| </div> |
| <div class="paragraph"> |
| <p>As already discussed, the <code>fixture</code> package provides classes to create sample objects, while the <code>SimpleModule</code> provides a fixture script to tear down all data from the module.</p> |
| </div> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="module-simples-srctestjava"><a class="anchor" href="#module-simples-srctestjava"></a>module-simple’s src/test/java</h3> |
| <div class="paragraph"> |
| <p>Under <code>src/test/java</code> we have:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/test/java/ |
| domainapp/ |
| modules/ |
| simple/ |
| dom/ |
| so/ <i class="conum" data-value="1"></i><b>(1)</b> |
| SimpleObject_Test.java |
| SimpleObjects_Test.java |
| integtests/ |
| tests/ <i class="conum" data-value="2"></i><b>(2)</b> |
| SimpleObject_IntegTest.java |
| SimpleObjects_IntegTest.java |
| SimpleModuleIntegTestAbstract.java <i class="conum" data-value="3"></i><b>(3)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>These are very simple unit tests of <code>SimpleObject</code> and <code>SimpleObjects</code> with the package structure the same as in <code>src/main/java</code>. |
| They are written in JUnit 5, and use JMockito as the mocking library.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Integration tests for the module. |
| These use the <a href="../../../refguide/latest/applib-svc/WrapperFactory.html" class="page">WrapperFactory</a> to simulate interactions through the UI.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>The <code>SimpleModuleIntegTestAbstract</code> superclass bootstraps the module’s integration tests. |
| This is discussed in more detail below.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| these integration tests are annotated with the Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/transaction/annotation/Transactional.html">@Transactional</a>, which means that Spring will automatically roll back the changes to the database; there’s no need to delete data afterwards. |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="admonitionblock important"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-important" title="Important"></i> |
| </td> |
| <td class="content"> |
| the naming convention — with <code>Test</code> and <code>IntegTest</code> suffixes — is important, because the Maven surefire plugin is configured to run multiple times, one <code><execution></code> for each suffix. |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="simplemoduleintegtestabstract"><a class="anchor" href="#simplemoduleintegtestabstract"></a>SimpleModuleIntegTestAbstract</h4> |
| <div class="paragraph"> |
| <p>The <code>SimpleModuleIntegTestAbstract</code> is the superclass of all integration tests in the module, annotated with <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html">@SpringBootTest</a>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">SimpleModuleIntegTestAbstract.java</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@SpringBootTest( |
| classes = SimpleModuleIntegTestAbstract.AppManifest.class <i class="conum" data-value="1"></i><b>(1)</b> |
| ) |
| @TestPropertySource({ <i class="conum" data-value="2"></i><b>(2)</b> |
| IsisPresets.H2InMemory_withUniqueSchema, <i class="conum" data-value="3"></i><b>(3)</b> |
| IsisPresets.DataNucleusAutoCreate, <i class="conum" data-value="4"></i><b>(4)</b> |
| IsisPresets.UseLog4j2Test, <i class="conum" data-value="5"></i><b>(5)</b> |
| }) |
| public abstract class SimpleModuleIntegTestAbstract |
| extends IsisIntegrationTestAbstractWithFixtures { <i class="conum" data-value="6"></i><b>(6)</b> |
| |
| @Configuration |
| @Import({ |
| IsisModuleCoreRuntimeServices.class, <i class="conum" data-value="7"></i><b>(7)</b> |
| IsisModuleSecurityBypass.class, |
| IsisModuleJdoDataNucleus5.class, |
| IsisModuleTestingFixturesApplib.class, <i class="conum" data-value="8"></i><b>(8)</b> |
| |
| SimpleModule.class |
| }) |
| public static class AppManifest { |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>The <code>AppManifest</code> (defined as a nested static class below) lists the modules needed to bootstrap the integration test.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Spring allows additional properties to be defined through the <a href="https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/context/TestPropertySource.html">@TestPropertySource</a> annotation</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>Runs the tests in memory using H2. |
| A unique schema allows tests to potentially be run in parallel</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>Ensures that JDO/DataNucleus is configured to create the database schema first. |
| This may be required because the application might otherwise be configured to use the <a href="../../../userguide/latest/flyway/about.html" class="page">Flyway integration</a>.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="5"></i><b>5</b></td> |
| <td>Sets up logging to use the configuration defined in the <code>log4j2-test.xml</code> file</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="6"></i><b>6</b></td> |
| <td>Tests typically inherit from <code>IsisIntegrationTestAbstract</code>, which provides some convenience methods to inherit from. |
| In this case, the test inherits from the <code>IsisIntegrationTestAbstractWithFixtures</code> subclass which also adds in support for running fixtures.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="7"></i><b>7</b></td> |
| <td>Specifies the modules that make up Apache Isis framework itself. |
| These include core, security set to the bypass implementation (effecively is ignored) and JDO/DataNucleus for persistence. |
| Note that there no viewers are bootstrapped because the tests are run through Spring’s integration testing framework, rather than (say) as Selenium tests.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="8"></i><b>8</b></td> |
| <td>Brings in support for running fixtures.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| You can learn more about testing in the <a href="../../../testing/latest/about.html" class="page">Testing Guide</a>. |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="webapps-srcmainjava"><a class="anchor" href="#webapps-srcmainjava"></a>webapp’s src/main/java</h3> |
| <div class="paragraph"> |
| <p>Under <code>src/main/java</code> we have:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/main/java/ |
| domainapp/ |
| webapp/ |
| application/ |
| fixture/ |
| scenarios/ <i class="conum" data-value="1"></i><b>(1)</b> |
| DomainAppDemo.java <i class="conum" data-value="2"></i><b>(2)</b> |
| DomainAppFixtureScriptsSpecificationProvider.java <i class="conum" data-value="3"></i><b>(3)</b> |
| services/ |
| health/ |
| HealthCheckServiceImpl.java <i class="conum" data-value="4"></i><b>(4)</b> |
| homepage/ |
| HomePageViewModel.java <i class="conum" data-value="5"></i><b>(5)</b> |
| HomePageViewModel.layout.xml |
| HomePageViewModel.png |
| ApplicationModule.java <i class="conum" data-value="6"></i><b>(6)</b> |
| AppManifest.java <i class="conum" data-value="7"></i><b>(7)</b> |
| SimpleApp.java <i class="conum" data-value="8"></i><b>(8)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Defines scenarios (fixtures) for setting up the system into a known state. |
| Used for prototyping and also integration testing.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>The <code>DomainAppDemo</code> is the fixture that was run <a href="#fixtures">earlier on</a>.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>The <code>DomainAppFixtureScriptsSpecificationProvider</code> is used to configure the run fixture script menu item shown on the "Prototyping" menu. |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| Fixture scenarios also need to be <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Import.html">@Import</a>ed, typically in the top-level <code>AppManifest</code>. |
| </td> |
| </tr> |
| </table> |
| </div></td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>An implementation of the <a href="../../../refguide/latest/applib-svc/HealthCheckService.html" class="page">HealtCheckService</a>. |
| This integrates with Spring Boot’s <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/actuate/health/HealthIndicator.html">HealthIndicator</a> SPI, surfaced through the <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html">Spring Boot Actuator</a>.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="5"></i><b>5</b></td> |
| <td>Annotated with <a href="../../../refguide/latest/applib-ant/HomePage.html" class="page">@HomePage</a> and so is shown automatically as the home page.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="6"></i><b>6</b></td> |
| <td>Defines the services in the webapp module, along with dependencies onto the other modules in the application.<br> |
| Discussed in more detail below.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="7"></i><b>7</b></td> |
| <td><code>AppManifest</code> is the top-level Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html">@Configuration</a> that specifies the components of Apache Isis to use, along with the modules making up the application itself (ie <code>ApplicationModule</code>, which depends in turn on <code>SimpleModule</code>).<br> |
| This is discussed in more detail below</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="8"></i><b>8</b></td> |
| <td><code>SimpleApp</code> is the <a href="https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/autoconfigure/SpringBootApplication.html">@SpringBootApplication</a> used to bootstrap the app. |
| It’s pretty much boilerplate - the important piece is that it references <code>AppManifest</code>.<br> |
| It’s discussed in more detail below</td> |
| </tr> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="applicationmodule"><a class="anchor" href="#applicationmodule"></a>ApplicationModule</h4> |
| <div class="paragraph"> |
| <p>The <code>ApplicationModule</code> defines the services in the webapp module, along with dependencies onto the other modules in the application. |
| It’s very simple though:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">ApplicationModule.java</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">package domainapp.webapp.application; |
| ... imports omitted ... |
| @Configuration |
| @Import(SimpleModule.class) <i class="conum" data-value="1"></i><b>(1)</b> |
| @ComponentScan <i class="conum" data-value="2"></i><b>(2)</b> |
| public class ApplicationModule { |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>This module depends on the <code>SimpleModule</code> module.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>specifies this class' package as a root to scan for Spring <a href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/stereotype/Component.html">@Component</a>s.</td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="appmanifest"><a class="anchor" href="#appmanifest"></a>AppManifest</h4> |
| <div class="paragraph"> |
| <p>The "app manifest" (the name has been retained from Apache Isis v1.x) is the top-level Spring <code>@Configuration</code>. |
| It looks like this:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">AppManifest.java</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Configuration |
| @Import({ |
| IsisModuleCoreRuntimeServices.class, <i class="conum" data-value="1"></i><b>(1)</b> |
| IsisModuleSecurityShiro.class, <i class="conum" data-value="2"></i><b>(2)</b> |
| IsisModuleJdoDataNucleus5.class, <i class="conum" data-value="3"></i><b>(3)</b> |
| IsisModuleViewerRestfulObjectsJaxrsResteasy4.class, <i class="conum" data-value="4"></i><b>(4)</b> |
| IsisModuleViewerWicketViewer.class, <i class="conum" data-value="5"></i><b>(5)</b> |
| |
| IsisModuleTestingH2ConsoleUi.class, <i class="conum" data-value="6"></i><b>(6)</b> |
| IsisModuleTestingFixturesApplib.class, <i class="conum" data-value="7"></i><b>(7)</b> |
| |
| IsisModuleExtFlywayImpl.class, <i class="conum" data-value="8"></i><b>(8)</b> |
| |
| ApplicationModule.class, <i class="conum" data-value="9"></i><b>(9)</b> |
| |
| DomainAppDemo.class <i class="conum" data-value="10"></i><b>(10)</b> |
| }) |
| @PropertySource(IsisPresets.NoTranslations) <i class="conum" data-value="11"></i><b>(11)</b> |
| @PropertySource(IsisPresets.DebugDiscovery), |
| public class AppManifest { |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Mandatory - specifies the core of the Apache Isis framework</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Enables the Shiro security mechanism. |
| There are several security implementations, precisely one must be selected</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>Enables JDO/DataNucleus for persistence. |
| Optional (though if omitted then only <a href="../../../userguide/latest/fun/overview.html#view-models" class="page">view models</a> may be used, with hand-rolled persistence).</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>Enables the <a href="../../../vro/latest/about.html" class="page">Restful Objects viewer</a> (ie REST API).</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="5"></i><b>5</b></td> |
| <td>Enables the <a href="../../../vw/latest/about.html" class="page">Wicket viewer</a></td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="6"></i><b>6</b></td> |
| <td>Enables the H2 Console (menu from the "Prototyping" menu), applicable only if running against h2 in-memory database.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="7"></i><b>7</b></td> |
| <td>Brings in support to run <a href="../../../testing/latest/fixtures/about.html" class="page">fixtures</a> within the application, eg for prototyping.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="8"></i><b>8</b></td> |
| <td>Enables the <a href="../../../userguide/latest/flyway/about.html" class="page">Flyway</a> integration.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="9"></i><b>9</b></td> |
| <td>References the application’s module(s), in this case just the one, <code>ApplicationModule</code>.<br> |
| This is discussed below.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="10"></i><b>10</b></td> |
| <td>Makes the fixture scenario classes available for discovery.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="11"></i><b>11</b></td> |
| <td>Normally configuration properties are picked up from Spring Boot’s <code>application.properties</code> or <code>application.yml</code> files, but additional properties can be overridden directly. |
| These two both use the <code>IsisPresets</code> convenience class, to disable i18n support and for additional debugging log statements.</td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="simpleapp"><a class="anchor" href="#simpleapp"></a>SimpleApp</h4> |
| <div class="paragraph"> |
| <p>The application is bootstrapped using <code>SimpleApp</code>, a regular <code>@SpringBootApplication</code>. |
| It is mostly boilerplate:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@SpringBootApplication |
| @Import({ |
| AppManifest.class, <i class="conum" data-value="1"></i><b>(1)</b> |
| }) |
| public class SimpleApp |
| extends SpringBootServletInitializer { |
| |
| public static void main(String[] args) { |
| IsisPresets.prototyping(); <i class="conum" data-value="2"></i><b>(2)</b> |
| SpringApplication.run( |
| new Class[] { SimpleApp.class }, args); |
| } |
| }</code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>references the <code>AppManifest</code> mentioned earlier</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>specifies prototyping mode. |
| This enables actions marked for prototyping to become available, useful during the early stages of development. |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| As an alternative to making this call, you can also just run with a system property <code>-DPROTOTYPING=true</code> |
| </td> |
| </tr> |
| </table> |
| </div></td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="webapps-srcmainresources"><a class="anchor" href="#webapps-srcmainresources"></a>webapp’s src/main/resources</h3> |
| <div class="paragraph"> |
| <p>Under <code>src/main/resources</code> we have:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/main/resources |
| config/ |
| application.properties <i class="conum" data-value="1"></i><b>(1)</b> |
| application-SQLSERVER.properties <i class="conum" data-value="2"></i><b>(2)</b> |
| db/ |
| migration/ |
| SQLSERVER/ |
| Vyyyy.mm.dd.hh.ss__xxx.sql <i class="conum" data-value="3"></i><b>(3)</b> |
| static/ <i class="conum" data-value="4"></i><b>(4)</b> |
| templates/ <i class="conum" data-value="5"></i><b>(5)</b> |
| application.yml <i class="conum" data-value="6"></i><b>(6)</b> |
| banner.txt <i class="conum" data-value="7"></i><b>(7)</b> |
| log4j2-spring.xml <i class="conum" data-value="8"></i><b>(8)</b> |
| menubars.layout.xml <i class="conum" data-value="9"></i><b>(9)</b> |
| shiro.ini <i class="conum" data-value="10"></i><b>(10)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>By convention, we use <code>config/application.properties</code> to hold configuration properties that change between environments (dev, test, prod). |
| Typically this just holds JDBC connection strings, etc.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Enabled if run using the <code>SQLSERVER</code> profile (eg using <code>-Dspring.profiles.active=SQLSERVER</code>). Configures to use a SQL Server database, and enables Flyway to set up the database schema</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>Flyway migration scripts.<br> |
| This leverages a feature in Spring Boot’s Flyway integration which allows different variants of scripts for different vendors to be stored, in a <code>db.migration.{vendor}</code> package.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>The <code>static</code> package (a <a href="https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-spring-mvc-static-content">Spring convention</a>) provides access for static resources that are accessible from the webapp</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="5"></i><b>5</b></td> |
| <td>The <code>templates</code> package holds a fallback error page, which is the <a href="https://www.baeldung.com/spring-thymeleaf-template-directory#change-default">default location</a> for pages rendered using Spring Boot’s integration with Thymeleaf.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="6"></i><b>6</b></td> |
| <td>By convention, we use <code>application.yml</code> to hold configuration properties that do <em>not</em> change between environments.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="7"></i><b>7</b></td> |
| <td>The <code>banner.txt</code> is shown when bootstrapping.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="8"></i><b>8</b></td> |
| <td>The <code>log4j2-spring.xml</code> configures log4j2 (the logging system used by Apache Isis)</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="9"></i><b>9</b></td> |
| <td>The <code>menubars.layout.xml</code> arranges the actions of the domain services into menus.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="10"></i><b>10</b></td> |
| <td>The <code>shiro.ini</code> file configures Shiro security integration (see the <code>IsisModuleSecurityShiro</code> module imported in the <code>AppManifest</code>, above). |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <p>The <a href="../../../security/latest/shiro/about.html" class="page">Shiro security</a> integration is much more flexible than simple file-based authentication.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div></td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>To call out some of the files under <code>static</code>:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>The <code>index.html</code> 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.</p> |
| </li> |
| <li> |
| <p>In <code>css/application.css</code> 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 <code>cssClass()</code> method in each domain object to provide additional CSS classes to target.</p> |
| </li> |
| <li> |
| <p>Similarly, in <code>scripts/application.js</code> you have the option to add arbitrary Javascript. |
| JQuery is available by default.</p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="no-srcmainwebapp"><a class="anchor" href="#no-srcmainwebapp"></a>No src/main/webapp</h3> |
| <div class="paragraph"> |
| <p>Note that there is no <code>src/main/webapp/</code> or <code>WEB-INF/web.xml</code> - the servlets and filters are configured by Apache Isis automatically.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="webapps-srctestjava"><a class="anchor" href="#webapps-srctestjava"></a>webapp’s src/test/java</h3> |
| <div class="paragraph"> |
| <p>Under <code>src/test/java</code> we have different sets of tests. |
| We’ll inspect each in turn.</p> |
| </div> |
| <div class="admonitionblock important"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-important" title="Important"></i> |
| </td> |
| <td class="content"> |
| the naming convention — with <code>Test</code>, <code>IntegTest</code> and <code>IntegBddSpecs</code> suffixes — is important, because the Maven surefire plugin is configured to run multiple times, one <code><execution></code> for each suffix. |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="sect3"> |
| <h4 id="bdd-specs"><a class="anchor" href="#bdd-specs"></a>BDD Specs</h4> |
| <div class="paragraph"> |
| <p>The simplapp starter app includes support for <a href="../../../testing/latest/specsupport/about.html" class="page">BDD (Cucumber)</a> specifications. |
| These reside under <code>domain.webapp.bdd</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/test/java |
| domainapp/ |
| webapp/ |
| bdd/ |
| glue/ |
| SimpleObjectsStepDef.java <i class="conum" data-value="1"></i><b>(1)</b> |
| specs/ |
| SimpleObjectSpec_listAllAndCreate.feature <i class="conum" data-value="2"></i><b>(2)</b> |
| RunIntegBddSpecs.java <i class="conum" data-value="3"></i><b>(3)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>defines the step definitions (or "glue") which describes how to interact with the application.<br> |
| This class inherits from <code>ApplicationIntegTestAbstract</code>, the base class for integration tests, described in the <a href="about.html#integration-tests" class="page">next section</a>.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>the feature file, discussed below.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>boilerplate used to run the BDD Cucumber tests using JUni5 4.x.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>There is just one feature file: <code>SimpleObjectSpec_listAllAndCreate.feature</code>, which is pretty simple:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-feature hljs" data-lang="feature">Feature: List and Create New Simple Objects |
| |
| Scenario: Existing simple objects can be listed and new ones created |
| Given there are initially 3 simple objects |
| When I create a new simple object |
| Then there are 4 simple objects</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The set up of the 3 initial objects is part of the step definitions.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="integration-tests"><a class="anchor" href="#integration-tests"></a>Integration Tests</h4> |
| <div class="paragraph"> |
| <p>The integration tests are in <code>domainapp.application.integtests</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/ |
| test/ |
| java/ |
| domainapp/ |
| webapp/ |
| integtests/ |
| metamodel/ |
| lockdown/ |
| approved/ |
| ... |
| current/ |
| ... |
| LockDownMetaModel_IntegTest.java <i class="conum" data-value="1"></i><b>(1)</b> |
| ValidateDomainModel_IntegTest.java <i class="conum" data-value="2"></i><b>(2)</b> |
| smoke/ |
| Smoke_IntegTest.java <i class="conum" data-value="3"></i><b>(3)</b> |
| ApplicationIntegTestAbstract.java <i class="conum" data-value="4"></i><b>(4)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>Uses approval tests to verify that the metamodel is unchanged between releases of Apache Isis.<br> |
| Discussed in more detail below.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>Bootstraps the app and runs the metamodel validators to check that there are not metamodel errors.<br> |
| This can also be done simply when running the application, but performing the checks through integration tests enables "fail-fast" checking, as part of CI, for example.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="3"></i><b>3</b></td> |
| <td>Performs a number of high-level smoke tests, to check that the core functionality works correctly.</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="4"></i><b>4</b></td> |
| <td>Base class used to bootstrap all integration tests for this module. |
| It is very similar to the base class used to bootstrap the integration tests for the simple module <a href="about.html#SimpleModuleIntegTestAbstract" class="page">about.adoc#SimpleModuleIntegTestAbstract</a>, but referencing <code>ApplicationModule</code> rather than <code>SimpleModule</code>.</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>The purpose of the metamodel lockdown tests is to capture regressions in Apache Isis itself whenever it is updated.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Normally the metamodel of the application will evolve all of the time, so the metamodel lockdown tests are disabled by default and only enabled with <code>-Dmetamodel.lockdown</code>. |
| If you want to capture the current metamodel, then enable and they will likely fail. |
| The new export of the metamodel will be in <code>current</code> and can simply be approved (by copying over to the <code>approved</code> directory.</p> |
| </div> |
| <div class="paragraph"> |
| <p>However, if you are upgrading Apache Isis then you may want to check that the metamodel being built by the next version of Apache Isis is the same as previous. |
| In this case, update Apache Isis (by updating the `<version> of the parent pom) and run the lockdown tests to check for differences.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="unit-tests"><a class="anchor" href="#unit-tests"></a>Unit Tests</h4> |
| <div class="paragraph"> |
| <p>The integration tests are in <code>domainapp.application.unittests</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code>src/test/java |
| domainapp/ |
| webapp/ |
| unittests/ |
| mavendeps/ |
| lockdown/ |
| approved/ |
| ... |
| current/ |
| ... |
| LockDownMavenDeps_Test.java <i class="conum" data-value="1"></i><b>(1)</b> |
| util/ |
| CurrentVsApprovedApprovalTextWriter.java <i class="conum" data-value="2"></i><b>(2)</b></code></pre> |
| </div> |
| </div> |
| <div class="colist arabic"> |
| <table> |
| <tr> |
| <td><i class="conum" data-value="1"></i><b>1</b></td> |
| <td>lock down test to check the transitive set of dependencies used by the application</td> |
| </tr> |
| <tr> |
| <td><i class="conum" data-value="2"></i><b>2</b></td> |
| <td>utility class used by the lock down tests (unit tests and integ tests).</td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>The maven dependency lock down tests are disabled by default, only enabled using <code>-Dmavendeps.lockdown</code>. |
| The <code>pom.xml</code> is configured to run the Maven <code>dependency:tree</code> and <code>dependency:list</code> goals, capturing the current dependencies. |
| These are compared to the approved versions.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Any time the Apache Isis version is updated, run these tests using <code>-Dmavendeps.lockdown</code> to capture and approve the new versions.</p> |
| </div> |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| The Maven dependency lock down tests are useful to capture any accidental changes to the dependency tree, so consider enabling them all of the time. |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="root-modules-pom-xml"><a class="anchor" href="#root-modules-pom-xml"></a>Root module’s pom.xml</h3> |
| <div class="paragraph"> |
| <p>In the parent module we of course have the <code>pom.xml</code>. |
| This inherits from <code>isis-app-starter-parent</code>:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="title">pom.xml</div> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><parent> |
| <groupId>org.apache.isis.app</groupId> |
| <artifactId>isis-app-starter-parent</artifactId> |
| <version>XXX</version> |
| </parent></code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>... which builds upon Spring Boot’s own <code>org.springframework.boot:spring-boot-starter-parent</code>. |
| This means:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p>the set of third party dependencies declared have been validated as compatible by Spring Boot team</p> |
| </li> |
| <li> |
| <p>build plugins are declared and configured appropriately</p> |
| </li> |
| <li> |
| <p>imports to the Apache Isis dependencies are declared via <code><dependencyManagement></code></p> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="running-from-within-the-ide"><a class="anchor" href="#running-from-within-the-ide"></a>Running from within the IDE</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>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 <a href="../../../setupguide/latest/about.html" class="page">Setup Guide</a> for details. |
| Basically, though, it amounts to running the <code>main()</code> method in the <code>SimpleApp</code>, but also (and this bit is important) ensuring that the <a href="#setupguide:hints-and-tips:about.adoc#datanucleus-enhancer" class="page unresolved">DataNucleus enhancer</a> has properly processed all domain entities.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Here’s what the setup looks like in IntelliJ IDEA:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/simpleapp-webapp.png"><img src="_images/simpleapp/simpleapp-webapp.png" alt="simpleapp webapp" width="600px"></a> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>which uses an IntelliJ feature to run a different run configuration to run DataNucleus enhancer beforehand:</p> |
| </div> |
| <div class="imageblock"> |
| <div class="content"> |
| <a class="image" href="_images/simpleapp/simpleapp-webapp-before-launch.png"><img src="_images/simpleapp/simpleapp-webapp-before-launch.png" alt="simpleapp webapp before launch" width="600px"></a> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="experimenting-with-the-app"><a class="anchor" href="#experimenting-with-the-app"></a>Experimenting with the App</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Once you are familiar with the app, try modifying it. |
| There is plenty more guidance on this site; start with the <a href="../../../userguide/latest/fun/about.html" class="page">User Guide Fundamentals</a> and then look at the other guides linked to from the top-level menu or from the main <a href="../../latest/about.html" class="page">table of contents</a>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>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 <a href="../../latest/support/about.html" class="page">support page</a>.</p> |
| </div> |
| </div> |
| </div> |
| </article> |
| <aside class="article-aside toc" role="navigation"> |
| <p class="toc-title">On this page</p> |
| <div id="article-toc"></div> |
| </aside> |
| </main> |
| </div> |
| <footer class="footer"> |
| <div class="content"> |
| <div class="copyright"> |
| <p> |
| Copyright © 2010~2020 The Apache Software Foundation, licensed under the Apache License, v2.0. |
| <br/> |
| Apache, the Apache feather logo, Apache Isis, and the Apache Isis project logo are all trademarks of The Apache Software Foundation. |
| </p> |
| </div> |
| <div class="revision"> |
| <p>Revision: SNAPSHOT</p> |
| </div> |
| </div> |
| </footer> |
| <script src="../../../_/js/site.js"></script> |
| <script async src="../../../_/js/vendor/highlight.js"></script> |
| <script src="../../../_/js/vendor/jquery-3.4.1.min.js"></script> |
| <script src="../../../_/js/vendor/jquery-ui-1.12.1.custom.widget-only.min.js"></script> |
| <script src="../../../_/js/vendor/jquery.tocify.min.js"></script> |
| |
| <script> |
| $(function() { |
| $("#article-toc").tocify( { |
| showEffect: "slideDown", |
| hashGenerator: "pretty", |
| hideEffect: "slideUp", |
| selectors: "h2, h3", |
| scrollTo: 120, |
| smoothScroll: true, |
| theme: "jqueryui", |
| highlightOnScroll: true |
| } ); |
| }); |
| </script> |
| </body> |
| </html> |