0
0

Rapid Development with AppStudio

Tutorial
902 / 1
Docs EInnovator Posted 09 Jun 20

Rapid Development with App Studio

App Studio is a cloud-based IDE to quickly create and deploy applications. Use cases range from simple or medium complexity applications for personal use, to large scale business enabling and missing-critical applications structured as a micro-service architecture.

In this tutorial, we provide a practical guide on how to get started developing application with EInnovator App Studio, using as example a application to manage a database of Superheros. We will start be showing how to create a project, and define the data-model for the application. Following that we will use the built-in templates to automatically generate a Web Controller Component and Views for listing, displaying, creating and editing Superheros. We will test the application from within the App Studio followed by actual deployment in a Cloud Environment, by generation and building a Spring Boot application automatically from the application model. In later section we will also show how to add role-based based security checks, and to notify users of relevant events in the application.

A complete implementation of this tutorial, is available as a free solution in the App Studio marketplace. Thus, in addition to follow this tutorial by starting from an empty project, you may also import the Supeheros marketplace project and review the complete solution with the aid of this tutorial.

Superheros

Core Concepts

EInnovator Studio provides an high-level rapid application development (RAD) environment, combining the simplicity of visual programming and the power of traditional programming and IDE. It provides a well-defined programming model based on the Model-View-Component paradigm, with an integrated security and user notification model. Built-in abstractions include: Data-Model Entities, Views, Components, Roles, Notifications, test Datasets and test users.

Several View and Component generation templates are available allow quickly bootstrap new application and business solution in minutes. The view and component generation is informed by the data model which provides information to what makes most sense to generate in a particular application. An extensive Widget component library is available (e.g. for content, forms, charts, and other use-cases) to allow full customization of look-and-feel of UIs.

Code generation is multi-Target, and a single project can have multiple Targets. Supported targets include server and client sides with different runtimes and stacks (e.g. Java with Spring Boot), pure front-end PWA, mobile native, and hybrid frameworks. Additionally, a built-in application execution emulator allow to preview, test and demo applications from the cloud IDE without having to deploy to the cloud. This is considered extremely useful as it accelerates considerable the development and experimentation process. Generate target code is pushed to Git repositories (one for each Target), thus allowing developers and business to retain full control and ownership of the code-base. Including following mixed programming methodologies where some of the artifacts are generated by the App Studio and target-specific fine-grained customization can be done using the underlying runtime and stack APIs, practices, and mechanisms. App Studio also support partial run-trip code generation, allowing existing code-based based to be partially mapped back to Studio style data-model and abstractions, thus effectively working as a cross-target code converter.

Cloud building and deployment is done with integration with EInnovator Cloud Manager and EInnovator Cloud — a Kubernetes based cloud environment. This allows to setup a fully integrated continuous delivery practice where the development cycle is interwoven with devops operations.

Optional integration with EInnovator Micro-Sertice Suite — a set of out-of-the-box services solutions for common functionally, from SSO Authentication, to user notifications, file persistence, and social interaction — further simplifies development as it allows individual applications develop with the App Studio to focus on the specific functionality of their business domain. This further speeds up the app development-to-production life-cycle, the real-world inception of the new solutions, and continuous exploration of new features and business ideas.

Getting Started: Creating the Project

First step to implement the Superheros application is to create a Project in the App Studio for the application. You will need first to register an account into EInnovator website, if you have not done so. Assuming you are already registered, navigate to https://studio.einnovator.org, and create a new project with name Superheros.

Select target type Service. with default settings, namely the default runtime Java, default stack Spring Boot, and default VDL Thymeleaf. This is not too important at this point, as you can later add additional Targets or change the Target type and settings. It is possible to preview, test, and demo the application from within the App Studio without performing a cloud build and deploy, so selecting a Target becomes important only when you want to build the app and deploy the app to the cloud for your users, or you want to push the target generated artifacts to a Git repository.

Image below shows the Project creation page, and the project dashboard page. Notice that the project dashboard has tabs to list and manage the key abstractions used to implement the project. Namely, the tabs Data-Model, Views, Components, Integration, Targets, and Settings.

Data Model

First step into creating an application is to define its data model. That is, the set of entities, associations, and support types together with their properties, that captures and represents the domain. For the Superhero project, we will use only one Entity named Superhero and one support Enum type named Squad.

Entity Superhero

Create entity of category Entity with name Superhero. Select as parent entity the built-in library entity EntityBase3*. This provides some basic fields to the Entity, like a unique id, a unique uuid, and creationDate.

Create another entity of category Enum with name Squad.

Open the dashboard for entity Superhero and add the properties below:

  • name of type String variant Text. Set as editor widget Input:Text. Enable filtering, and set as filtering property q with operator contains. Enable also the Table Column option. While these setting are not strictly necessary, they inform view and component generation with makes it easier and faster to get the app to prototype stage.

  • img of type String varient Image:URL. Set as editor widget Upload:Media.

  • description of type String variant Text. Se as editor widget Textarea. Enable filtering, and set as filtering property q with operator contains (same as for property name).

squad of type Squad (the enum you created earlier). Set as editor widget Select. Enable filtering for this property.

  • villian of type Boolean. Set as editor widget Checkbox.

Squad Enum

We already already created enumerated Squad but did not specify which values are possible. Open the dashboard for enum Squad, and navigate to the tab Dataset. Each enumerated can have a set of static values, each with two (and possibly other) properties, namely value and displayValue. Add two values to Squad:

  • MARVEL value, with displayValue = Marvel
  • DC value, with displayValue = DC

One-to-Many Association

So far the data-model in very simply in the sense that there is no association between entities. To make it more realistic and interesting let’s define an additional property named friends as a One-To-Many association between each Superhero and a set of other Superheros. Set the type of this property to List with element type Superhero.

Review the defined data-model in the the tab Data-Model > Data-Graph.

Something useful to do before moving forward is to generate a dummy dataset of instances of Entity for the purpose of later testing the app. In the dashboard of entity Supehero, tab Dataset click Generate Values. Select a instance count of 100. Confirm that 100 instance of dummy Supeheros have been created, using automatically generated value for the different properties, including name and description, and an identicon for the image.

Generating and Editing Views

Now that we have a data model we should create a set of Views that can be used to list, display, create, edit, and manage the instance of type Superhero.

Listing View

On project tab View, click Add View. Select as view type, Fragment and view category Entity List. Select entity Superhero. Leave the other settings with default values.

Once the view is generate you should see the dashboard of the View the generated widget tree as shown below.

You can preview the View in tab Preview. Notice that data in the dummy dataset is being used for provide the data for the listing.

We also want that the project View have a user-friendly and consistent layout, so we will create a page with a layout that include the Entity List Panel. On project tab View, click Add View, and select as view type, Page. Select one of the provide layout — e.g. a two-column layout. Select the previous created fragment Entity List Panel as imported sub-view. This is shown in screenshot below.

Once the page view is created, preview it. Confirm that the page has the selected layout, and import the listing panel showing the details of the dummy Superheros.

You many not fully be happy about the ordering of the fields as they show in the table. Fortunately, the App Studio View editor makes it very easy to customize the generate views, or even create completely new View from scratch, using drag&drop and widget configuration panel. Try drag&drop the TH and TD columns widget, so that the columns are shown in the following order: img, name, squad, vilian, and friends. Use preview as much as need to help you guide trough the process.

You many also want to change the look&fell of the page. Click on the widget created and edit some style properties in the widget property editor panel on the right side. Experiment with color, background, fonts, borders, margin and padding, etc.

Details View

We can repeat similar steps as above for the Supehero details view. On project tab View, click Add View. Select view type Fragment and view category Entity Details Panel. Select entity Superhero. Leave the other settings with default values. Preview the generate view. Use drag& drop to move the Image to top of the panel, and the widgets for the description and friends to the bottom.

Next, create another view of type Page. Select same layout as before. Select the previous created fragment Entity Details Panel as imported content sub-view.

Editor View

Finally, let create a editor panel to create new instances or edit existing instance of Superheros. On project tab View, click Add View. Select view type Fragment and view category Entity Editor Panel. Select entity Superhero. Leave the other settings with default values. Preview the generate view. Use drag& drop to MediaUpload* widget to the top of the panel, and the widgets for the description and friends to the bottom.

Next, create another view of type Page. Select same layout as before. Select the previous created fragment Entity Editor Panel as imported content sub-view.

Generating a Web Controller

Once we have generate and customize the Views, we can move forward to generate the components needed to drive the application. The most important component is a Web Controller to control the rendering of the Superhero pages and data. This is the only component that we will strictly need run and test the app from within the App Studio with the built-in emulator. Other components if needed, are implicitly created by the emulator.

On project tab Components, click Add Component. Select component type Web Controller, and component template Entity CRUD. Select entity Superhero. Leave the other settings with default values. This will create a component named SuperheroController.

Confirm that the SuperheroController is create with success, with several methods each with a body of instructions. This methods implements the basic CRUD workflow to list, create, and edit instances of Superhero. The generated methods and instructions body are usually enough to get started with the project, and rendering the generated view. However, it is always possible to extend and modify the existing methods and add new methods to the component. App Studio offers an intuitive mixed visual-imperative programming model, that should be easily understandable by starting developer but powerful enough to support complex use cases and the sophistication of experienced developer.

Most methods in this generated component have an associate endpoint mapping, with an HTTP method and an associate URL path. The component SuperheroController defines also a based endpoint path prefix /superhero. So the actual endpoints concat this prefix with the path specified in each endpoint method. The generated endpoints are summarized and explained below:

  • GET /supeheros list() ‐ Render the lists of Supeheros
  • GET /supeheros/{id} show() ‐ Renders the details page of a particular Supehero uniquely identified by the id in the path.
  • GET /supeheros/create create() ‐ Renders the Supehero creation form page
  • POST /supeheros createPost() ‐ Processes a submitted editor data (form in a web app) and create a new instance of Superhero. Redirect to the details page if the creation is successful.
  • GET /supeheros/{id}/edit edit() ‐ Edits the details of an existing Superhero
  • PUT /supeheros/{id}/edit editPut() ‐ Processes a submitted editor data (form in a web app) and updates the instance of Superhero. Redirect to the details page if the creation is successful.
  • DELETE /supeheros/{id} delete() ‐ Deletes the instance of Superhero with specified id. Redirect to the listing page after deletion.

An additional method of category ExceptionHandler is also generated. This is method captures and processes any error Exception sent by other methods.

Looking at the body of the generated method, you should notice that the ones that render a view complete the processing with instruction RENDER. This is the instruction used to select the view to render. The parameter of the RENDER is the name of the view. Confirm that those view name match and are bound to the View pages create earlier. If this is not the case (e.g. if you changed the default view names), select the view as appropriate.

Similarly, the methods that perform a redirect do this with instruction REDIRECT. The parameter of this instruction specifies which other HTTP endpoint should be rendered next. Confirm that the endpoint path match and are bound to other endpoints in this component. If you change the path of some the method endpoints, you should update the path as well in the REDIRECT instructions that should reference that endpoint.

Testing the App

Next we want to test the application, using the built-in emulator and interacting with the app. Select the Test tab in the SuperheroController dashboard. Select an endpoint method to test, starting with the method list() mapped to endpoint /superhero. Press Submit.

Confirm that the page with the list of Superheros is rendered. Do a a quick search on the list of Superhero by typing some query on the filter widgets.

Next, click on the hyper-link with the name of any of the Superhero, and confirm that the details page is rendered. Press the Back button, and do this for other instances as well. Press also Edit and change the details of some of the instances.

For all pages, listing, details, and editor, you should confirm that the pages rendered are exactly the ones that you had previewed already. Previewing the page allow to do guide the creation of the look&feel. However, experimenting with and testing a Web Controller component allows to fully experience the app and UI/UX workflow as the a real final user will experience. Thus, going beyond what can be done only by previewing a View. Moreover, the data model variables used in rendering each view are fully determined by workflow, rather than being “mocked” and statically selected.

In the details page, press Delete and confirm that a delete confirmation modal show up. Choose to delete the Superhero and confirm that you are redirect again to the listings page. In other tab, open the entity dashboard for the Superhero entity, and confirm that delete entity is not longer present in the dummy dataset.

Improving the App

The Views and controller code generated automatically provides a good starting point to build the Superhero application. More often than not, we want to go further than the vanilla solution produced mostly automatically by the App Studio templates. To demonstrate how one goes about extending a basic application, we introduce the requirement of rendering a donut chart showing the relative proportion of Supeheros of each Squad (i.e. Marvel vs. DC). This involves three steps:

  • Defining a Repository component with a suitable query. We will use a group by query.
  • Invoke the method in Repository component implementing the query, and exporting the query result to the listing view. This will be done from the SuperheroController.list() method.
  • Add a Chart widget to the listing view Superhero Table (e.g. between the filter and the table), and configured appropriately..

Creating a Repository Component

In addition to Web Controller components as the one we created earlier, App Studio supports additional categories of components. Such as Rest Controllers, Managers, Repositories, and Event Listeners. A common pattern is for each Entity in a project to have one of each of these components, namely Repositories to define custom queries, and Managers to perform business functionality beyond pure DB quering. Managers and Respositories are implicit created by the App Studio to cover basic operations, while the other types of components which implements different kinds of presentation layers should be created explicity – often using the built-in templates as starting point.

For the Superhero app we want to create a custom Repository to add a custom query to group and count the number of Supeheros in each Squad. On project tab Components, click Add Component. Select component type Repository, and component template Entity CRUD. Select entity Superhero. Leave the other settings with default values. This will create a component named SuperheroRepository.

Confirm that the component SuperheroRepository is create with success, with several query methods created. These repository methods don’t have body made of instructions, rather they represent queries whose semantic is inferred form the name of the method or for more advanced use case from explicit query clauses. The methods already created implement basic CRUD functionality – i.e. create, retrieve one or many, update, and delete, for instances of Superhero. We now want to add one additional method name countGroupBySquad().

In the dashboard of component Superhero controller, click Add Method to open the method creation modal. Enter method name countGroupBySquad(), without any parameters. Confirm that the method is created and shows up below the other pre-generated methods. This method will return a list of maps (key-value pairs) of the form {count=N, squad=Squad}.

Exporting Modal Variables

Next step is to invoke the method SuperheroRepository.countGroupBySquad() from the method SuperheroController.list(). Navigate to the dashboard of the SuperheroController component, and notice the instructions toolbar on the top. Drag the instruction EXPORT and drop in the method list() before the RENDER instruction. The EXPORT instruction is used to make data available during a view rendering. It takes two parameters, one for the name to give to the exported variable and another for the expression to assign to the variable. Enter squadCounts as variable name and superheroRepository.countGroupBySquad. This is shown in the image below.

Rendering Charts

Finally, we want to modify the Superhero Table view to render in addition to the filter, and table, a donut chart to display the relative counts of Superhero per Squad. Navigate to the dashboard of the view Superhero Table. Notice the widget toolbar on the top. Click on the Graph widget category button, and drag a Chart widget to the view above the table and below the filter subview. Click on the Chart widget to edit the properties. Sel the type of the chart as Donut. Next, click on Add Dataset. Enter in the Expression attribute the value ${squadCounts.count} and in the X Expression attribute the value ${squadCounts.squad}.

To test the chart rendering, go back to the SuperheroController dashboard Test tab. Select the again the endpoint method list() mapped to endpoint /superhero, and press Submit. Confirm the donut chart is rendered, as show in the the image below.

Building and Deploying to the Cloud

After some tinkering, iteration, and interactive testing of the app, one might want to make a first deployment to the cloud. For this, we need to select a Target to generate code to and a cloud platform to deploy. In the Superhero Project dashboard, go to tab Targets. If you had selected the target Service at project creation time, there should be a tab for it already. In the Java Service > Settings tab, confirm that the runtime Spring Boot and VDL Thyemeleaf is selected.

To generate code for a Target we need first to configure a Git repository where the artifacts will be pushed. Click on Add Repository and select a GIT

In the Generate tab, press Generate. Confirm that a list of artifacts

Role-Based Security Model

Notifying Users

Deploying the App to EInnovator Cloud

With the Docker image in place, we are now fully ready to deploy the app to the cloud. We just need to make sure that the DB connection is configured appropriately also in the cloud environment. Fortunately, this is done automatically by EInnovator Cloud Manager if you specify a suitable Stack setting for the app.

TODO 3-4: Deploy the App in the Cloud with a MySQL binding

  • From the Space Dev page, press button to Deploy to deploy your app.
  • Enter the image name superheros from DockerHub public registry. (The display name, and unique name of the app are set automatically from the image name, although you can change if you want.)
  • Select stack Suite / Boot to tell the Cloud Manager, that the app is built using a Spring Boot stack, and additionally makes use of several services in EInnovator Micro-Service suite.
  • Leave the settings for the instance count and resources on the default values (1 instance, 1G memory, 1G storage).
  • Keep the auto-create checkbox for Bindings. This ensures that the environment variable spring.datasource.* is set with values picked-up from the MySQL connector named superheros/root. Make sure that the unique name of the app (superheros) matches the name of the database.
  • Keep the auto-create checkbox for EnvVars checked. This ensures that the environment variable server.port is to port mapped in the container (80 by default).
  • To have the app start automatically, keep the Auto-Start checkbox checked. Alternatively, you might prefer first the deployment and then started using the toolbar.
  • Select a host for your app in the created domain, or keep the default. This makes the app available in URL http://superheros.myusername.nativex.cloud.
  • Deploy the app.
  • Wait till app and the container instance is in Running state. Should not take more than a few seconds.
  • Check the logs, and confirm that no error occurred.
  • On the Routes tab, confirm that a Route has been created. Click on View Application button, and confirm that the app home page opens.

Deploying a SSO Gateway

The default setting for the SSO Gateway server out of the blueprint https://sso.samples.sandbox.nativex.cloud, uses a pre-deployed shared virtual server with name samples running in Sandbox plan/mode. You want to change this, so you can have your own set of users, configure and administer the server, or even customize the look&fell of the server UI as seen by your users. There is can be done in two broad variations: your own sandbox like the samples on, but with your owns database and a different name, or a dedicated server paid plan. With the Sandbox you are limited to a user pool of 100 users and limited request rate of 100 requests/hour, which is makes it mostly useful for early learning and exploration like following this tutorial. For real world development, you will want to upgrade to a dedicated server. The steps to follow to deploy a Sandbox or dedicated server are almost the same, but with the dedicated deployment you can obviously customize resources size like memory, number of instances, unlimited request rates, have enhanced security, and so forth.

TODO 4-1: Deploy a SSO Gateway

  • Assuming you continue login in EInnovator Cloud Manager, and in Space MyApps - dev click on the Manage tab in the MySQL deployment, and the Database sub-tab. Create a Database named sso by clicking on button Add Database
  • Next, click on the Environment tab in the MySQL deployment, and the Connectors sub-tab. Create new connector, for database sso and user root, which should get the automatic name of sso/root.
  • Install a SSO Gateway Markteplace Solution, in Sandbox or dedicated plan. Keep the default host name sso and your previouslly created domain. Keep the auto-deploy checkbox checked.
  • Confirm that the container running the SSO is running. Use the status indicators, the logs and/or instance meta-data to confirm this.
  • On the Routes tab, confirm that a Route has been created. Click on View Application button, and confirm that the app Admin registration form show up. This admin registration page shows up because there is no user registered yet, and the server assumes that the first user to register is the Administrator.
  • On the admin registration form, enter your personal details and select a username and password.
  • Confirm that registration is successful, and that the browser navigates to the admin console of the SSO Gateway.
  • Feel free to explore the admin console, as well the regular user facing pages by pressing Back to Site. This allows you to edit your personal profile page, setup your organization, invite other users for you organization, etc. From the admin console, you can also fully manage you administer your user population, such as sending join invites, change user status, add them to groups as administrator, check site statistics in the admin dashboard, etc.

Security Configuration: Custom Roles and Access Control

Some of the great features of the SSO Gateway in EInnovator micro-service suite include the ability for different kinds customization. In other tutorial, we discuss in detail how to customize the UI, create custom UI themes, custom signup and registrations pages, branding and customization of notification templates, among other aspects — Custom Themes. In this tutorial, we focus on how to perform role based access control with custom roles.

When an application starts it registers in the SSO Gateway. Exactly what is registered can be configured in the property sso.registration in application.yml. In particular, we can register custom roles used to role based access control in out Superheros app, while benefinting from the role assignment and security management available in the admin UI of the SSO Gateway. Roles can be of two types Global Roles and Group Roles. In the Superheros app, we will use only Global roles. In particular, we want to define a global role Superhero Manager which is required to delete Superheros created by other users.

Sending Users Notifications

To improve user engagement we want the Superheros app to send notifications to users when certain events occur. In particular, we want notifications when a Superhero is updated to the user that first created the Superhero or last modified it, and to users with role SUPERHERO_MANAGER when a new Superhero is created or updated. Additionally, we want uses to receive notification via multiple channels, including email, SMS, and in app, and be able to customize their notification preferences. For this purpose, we will deploy the Notifications Hub of the EInnovator microservices suite and refactor the app to register new three new kinds of notifications on startup. A bonus point of using the Notifications Hub is that as app admins we can send newsletters and other email communications to our users (e.g. about Superheros* inside stories and news about app updates), or even perform SMS based campaigns.

TODO 7-2: Deploy the Notification Hub marketplace service.

  • Use the Cloud Manager to install the Notification Hub as a Marketplace Solution, in Sandbox or dedicated plan. Keep the default host name notifications and use (one of) your previously created domain. Keep the auto-deploy checkbox checked. Deploy the service.
  • Confirm that the Notification Hub service is deployed with success. Use the status indicators, the logs and/or instance meta-data to confirm this.
  • On the Routes tab, confirm that a Route has been created. Click on View Application button, and confirm that app file manager UI shows up. Press the notification Preferences button.
  • Back to the Cloud Manager restart the SSO Gateway and the Document Store in space MyApps - Dev. Wait for the services to restart. Check the logs first lines, and confirm that both services manage to register in the Notifications Hub.
  • Back to the Notifications Hub browser tab, reload the Preferences page, and confirm that notification preferences for SSO and Document show.

Social Media: Posting Comments

Superheros are usually popular and have lots of fans (and some detractors). We would like fans and detractors to be able to post comments and have discussions related to Superheros. Rather than reinventing the wheel and develop a commenting and social discussion functionality from the ground-up for specifically for the Superheros, will the more convenient approach of integrating the app with the Social Hub service from EInnovator micro-service suite. Specifically, we want to have a general Superhero discussion forum, and will want each Superhero details page to have its own dedicate discussion channel. Social Hub also support additional features like social impressions (e.g. likes and star ratings) case we decide to integrate that later.

TODO 8-1: Deploy the Social Hub marketplace service.

  • Use the Cloud Manager to install the Social Hub as a Marketplace Solution, in Sandbox or dedicated plan. Keep the default host name social and use (one of) your previously created domains. Keep the auto-deploy checkbox checked. Deploy the service.
  • Confirm that the Social Hub service is deployed with success. Use the status indicators, the logs and/or instance meta-data to confirm this.
  • On the Routes tab, confirm that a Route has been created. Click on View Application button, and confirm that UI shows up.

TODO 8-2: Configure the Superhero app to use Social Hub.

Full access to generated source-code in own provided Git/VCS repositories. Round-Trip Code Generation with cross-model and language mappings. Integrated cloud builds and deployment with Integration with EInnovator Micro-Service Suite for modularity, scalable and robust distributed architectures. Integrated issue tracking for easy of coordination between developers, teach-leads, managers, and clients. Opt-in Project Ticket support. Marketplace of Solutions, Themes, Components and Widgets

Summary

In this getting started tutorial, we learn how to build microservice-enabled application for management of Supeheros using EInnovator micro-services. We build a docker image for the app and deployed to the cloud using the Cloud Manager. We installed different marketplace solutions. The SSO Gateway for authentication and role-based access control. The Document Store for file upload persistence. The Notification Hub for sending notification to users about Superheros updates. And Social Hub to setup a discussion forum and post comments about the Superheros.

Exercises

Some suggested exercise extending the Superheros app:

  • Add a new field Superhero.locked, and update the access control rules so that Superheros with property locked=true can only be updated by users with role SUPERHERO_MANAGER
  • Update the notification publishing rules so that a message is automatically posted to the general discussion forum when a new superhero is created. Do this by returning the target selector "#superheros" in method SuperheroManagerImpl.getTargetsCreate().

Learning More

Comments and Discussion

Content