Software Architecture (2017/18)kti.tugraz.at/staff/rkern/courses/sa/Web Architecture...

29
VO/KU (706.706/706.707) Software Architecture (2017/18) Web Architecture - Java Web Application Tutorial Roman Kern ([email protected]) Heimo Gursch ([email protected]) http://kti.tugraz.at/staff/rkern/courses/sa/ http://isds.tugraz.at/

Transcript of Software Architecture (2017/18)kti.tugraz.at/staff/rkern/courses/sa/Web Architecture...

VO/KU (706.706/706.707)

Software Architecture (2017/18)

Web Architecture - Java Web Application Tutorial

Roman Kern ([email protected])Heimo Gursch ([email protected])

http://kti.tugraz.at/staff/rkern/courses/sa/

http://isds.tugraz.at/

Contents

1 Introduction 31.1 About this document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Dropwizard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.3 Angular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Application Layout and Setup 52.1 Create the Maven Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 Angular Project Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.3 Final Project Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

2.3.1 Java Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.3.2 Angular Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 Application 153.1 Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

3.1.1 WebApplication.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.1.2 WebResource.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.1.3 Request.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.1.4 Response.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.1.5 WebConfiguration.java . . . . . . . . . . . . . . . . . . . . . . . . . . 19

3.2 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203.3 HTML and TypeScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.3.1 app.module.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.3.2 app.component.html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.3.3 app.component.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.3.4 sa-http.service.spec.ts . . . . . . . . . . . . . . . . . . . . . . . . . 223.3.5 sa-http.service.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223.3.6 request.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243.3.7 response.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243.3.8 sa-main.component.html . . . . . . . . . . . . . . . . . . . . . . . . . . 253.3.9 sa-main.component.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

4 Compiling and running the complete application 27

List of Figures 28

Listings 29

2

1

Introduction

1.1 About this document

This document is aimed at students attending the Software Architecture lecture. During the course of thislecture, a web application needs to be implemented. This manual gives some insights to set up a webApplication in Java, HTML and JavaScript using Maven and the Frameworks Dropwizard and Angular.

1.2 Dropwizard1

Web application development in Java was accompanied by Java application servers like Apache Tomcat,GlassFish, IBM WebSphere, JBoss, Jetty, etc. Such web application servers could contain multiple webapplications at once. These full scale web application server come with some drawbacks like

• It is problematic/complicated to separate the applications within the application server,

• the assignment of dedicated resources is tricky,

• depending on the server used, there might occur scaling difficulties.

In many installations these problems are solved by just having one web application in a singe webapplication server. But then the question arises why the full-scale web server is necessary at all. Hence,embedded versions of Java application servers have been develop. Notable examples include

Jetty Embedded https://www.eclipse.org/jetty/documentation/current/embedding-jetty.html

Tomcat Embedded https://tomcat.apache.org/download-80.cgi.

These embedded severs are more light weighted and can be integrated in other software projects as simplelibraries. In some cases these embedded servers might lack infrastructural functions, like logging oruser management. Therefore, additional libraries are needed. Projects like Dropwizard where started tocombine embedded application servers with the necessary libraries to facilitate a large software project.The goal of all of these projects it the creation of still lightweight libraries which allow the fast and simplecreation of web applications by offering all required standard components. There are some projects tryingto achieve this goal, examples—and therefore Dropwizard competitors—are

Spring boot https://projects.spring.io/spring-boot/

Spark http://sparkjava.com/

1http://dropwizard.io/

3

Play https://www.playframework.com.

Software developed with one of these frameworks are often called micro services.In this tutorial Dropwizard will be used as an example for a modern, lightweight library to create

fully self managed web application. Dropwizard combines existing Java libraries to create the necessaryframework needed by a web application. Dropwizard includes:

Jetty in in embedded mode Does all the HTTP stuff

Jersey Java API for RESTful Web Services (JAX-RS)

Metrics Performance monitoring

Guava Google Java library providing a large amount of useful stuff

Jackson Mapping between Java objects and JSON

JDBI SQL database connection and object mapping

Logback and slf4j Logging

Miscellaneous Some other small stuff

In this tutorial Dropwizard will be used to serve static and dynamic content. The "Getting Started" manualat http://www.dropwizard.io/1.2.0/docs/getting-started.html shroud give a theneeded information to complete this tutorial.

1.3 Angular2

Angular is a JavaScript framework to map dynamic data to the static page layout. It fills the dynamic datacoming from the server into the HTML Layout and feeds user inputs back to the server. Angular takesover the task of manipulating the HTML DOM-tree and the communication with the server. In this manualjust very few features of Angular are shown. The curious reader is referred to one of the many Angulartutorials like https://angular.io/tutorial. With Angular so called Singe-Page Applications(SPAs) are created. A SPA consists of only one HTML page, where parts of the HTML-DOm tree arechanged to show different data and react to user inputs.Angular is currently available in version 5. There was a major change many aspects of Angular fromversion 1 to version 2. To highlight this big change, version 1 of the framework was called AngularJS andfrom version 2 onwards the framework is just called Angular.

In this tutorial no formatting of the HTML page is done. In many project Twitter Bootstrap3 is used toassist with the formatting. Bootstrap is a great help to reduce the work when dealing with CSS formattedHTML pages.

2https://angular.io/3https://getbootstrap.com/

4

2

Application Layout and Setup

2.1 Create the Maven1 Project

The complete Java software is handled as an Maven project. Maven is a build tool which manages theJava dependencies and overlooks the building process. Gradle2 is an more modern alternative achievingthe same and even more as Maven. A Maven project can be initiated in an IDE (Integrated DevelopmentEnvironment) of your choice. Eclipse, IntelliJ, NetBeans and other Java focused IDEs supporting Mavenshould work perfectly well. The first thing is to create a new Maven project. In this tutorial the project iscalled SaWebApp, shorthand for Software Architecture Web Application. In this tutorial Maven version 3is used and the project is named with

Project name SaWebApp

Artifact ID SaWebApp

Group ID at.tugraz.isds.sawebapp

Version 1.0.0-SNAPSHOT

Package at.tugraz.isds.sawebapp

When using Maven directly and not interacting with it by your IDE, the line

1 mvn -B archetype:generate -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=at.tugraz.isds -DartifactId=SaWebApp

Listing 2.1: Maven command line instructions to create the project

creates a new Maven project. When using an IDE, use the dialogues to create a new Maven project andname it accordingly. When the project in generated, it can be compiled with

1 mvn compile

Listing 2.2: Maven command line instructions to compile the project

and packaged with

1 mvn package

Listing 2.3: Maven command line instructions to build and package the project

Both commands have to be executed in the newly generate project directory so that Maven finds thepom.xml descriptor. Further information on using Maven can be found at https://maven.apache

1https://maven.apache.org/2https://gradle.org/

5

.org/guides/getting-started/maven-in-five-minutes.html. It is strongly advisedto use an IDE, than all this Maven command line stuff is hidden from you.

Maven generates the basic directory structure. Figure 2.1 shows the basic empty directory structure.This structure needs to be extended by some other files and directories. This will be explained later on.

Figure 2.1: Basic empty directory structure as it is generated by Maven

The automatically generated pom.xml needs to be extended too. At the end, the pom.xml should looklike

1 <?xml version="1.0" encoding="UTF-8"?>2 <project xmlns="http://maven.apache.org/POM/4.0.0"3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/

xsd/maven-4.0.0.xsd">5 <modelVersion>4.0.0</modelVersion>6 <groupId>at.tugraz.isds.sawebapp</groupId>7 <!-- name of the app -->8 <artifactId>SaWebApp</artifactId>9 <version>1.0.0-SNAPSHOT</version>

10 <packaging>jar</packaging>11 <!-- set the source encoding and JDK version -->12 <properties>13 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>14 <maven.compiler.source>1.8</maven.compiler.source>15 <maven.compiler.target>1.8</maven.compiler.target>16 <dropwizard.version>1.2.0</dropwizard.version>17 <dropwizard.redirect.version>1.0.5</dropwizard.redirect.version>18 </properties>192021 <build>22 <plugins>23 <!-- The Maven shades plugin generates an all-in-one ("fat") jar at24 the end of the building process. The web application is then fully25 contained in this jar. Only this fat-jar and the configuration files26 need to be shipped to the customer. -->27 <plugin>28 <groupId>org.apache.maven.plugins</groupId>29 <artifactId>maven-shade-plugin</artifactId>30 <version>3.1.0</version>31 <configuration>32 <createDependencyReducedPom>true</createDependencyReducedPom>33 <filters>34 <filter>35 <artifact>*:*</artifact>36 <excludes>37 <exclude>META-INF/*.SF</exclude>38 <exclude>META-INF/*.DSA</exclude>39 <exclude>META-INF/*.RSA</exclude>

6

40 </excludes>41 </filter>42 </filters>43 </configuration>44 <executions>45 <execution>46 <phase>package</phase>47 <goals>48 <goal>shade</goal>49 </goals>50 <configuration>51 <transformers>52 <transformer implementation="org.apache.maven.plugins.shade.resource

.ServicesResourceTransformer" />53 <transformer implementation="org.apache.maven.plugins.shade.resource

.ManifestResourceTransformer">54 <mainClass>at.tugraz.isds.sawebapp.WebApplication</mainClass>55 </transformer>56 </transformers>57 </configuration>58 </execution>59 </executions>60 </plugin>6162 <!-- generate JavaDoc JAR -->63 <plugin>64 <groupId>org.apache.maven.plugins</groupId>65 <artifactId>maven-javadoc-plugin</artifactId>66 <version>2.10.4</version>67 <executions>68 <execution>69 <id>attach-javadocs</id>70 <goals>71 <goal>jar</goal>72 </goals>73 </execution>74 </executions>75 </plugin>7677 <!-- generate sources JAR -->78 <plugin>79 <groupId>org.apache.maven.plugins</groupId>80 <artifactId>maven-source-plugin</artifactId>81 <version>3.0.1</version>82 <executions>83 <execution>84 <id>attach-sources</id>85 <goals>86 <goal>jar</goal>87 </goals>88 </execution>89 </executions>90 </plugin>9192 </plugins>93 </build>9495 <!-- Dropwizard dependencies -->96 <dependencies>97 <!-- Dropwizard itself -->98 <dependency>99 <groupId>io.dropwizard</groupId>

100 <artifactId>dropwizard-core</artifactId>

7

101 <version>${dropwizard.version}</version>102 </dependency>103 <!-- Static assets bundle - Needed to serve static resources like104 HTML- and JS- files. -->105 <dependency>106 <groupId>io.dropwizard</groupId>107 <artifactId>dropwizard-assets</artifactId>108 <version>${dropwizard.version}</version>109 </dependency>110 <!-- Redirect Bundle - Needed to redirect users from the plain the web111 address to the index.html file -->112 <dependency>113 <groupId>io.dropwizard-bundles</groupId>114 <artifactId>dropwizard-redirect-bundle</artifactId>115 <version>${dropwizard.redirect.version}</version>116 </dependency>117 </dependencies>118119 </project>

Listing 2.4: Content of the pom.xml file

The implementation of the Java application is continued in the Section 3.1.

2.2 Angular Project Setup

Similarly to Maven in the Java word, also in the web development world helpers and frameworks havebeen created. Many of this tools in the web development domain use Node.js3 as an execution platform.Some important examples are:

Yeoman is a scaffolding tool. This means it sets up the necessary file and folder structure4

Bower manages packages and dependences, so that there is no need to manually link them into yourcode5

Grunt is a build system to build, preview and test an application6

Gulp alternative to Grunt7

Karma to run tests8

Angular-Cli is a multi-aspect of tool specially designed to work with Angular9. Angular-Cli will be usedas the tool of choice throughout this project.

To proceed with the Angular-Cli setup, NodeJS must be installed and an NodeJS console opened. NodeJSoffers its own packet management system. To update all installed packages on NodeJS the instruction

1 npm update -g

Listing 2.5: NodeJS instruction to update all packages

has to be issued. Angular-Cli can be installed afterwards with3https://nodejs.org/4http://yeoman.io/5https://bower.io/6http://gruntjs.com/7https://gulpjs.com/8https://karma-runner.github.io/9https://github.com/angular/angular-cli

8

1 npm install -g @angular/cli

Listing 2.6: NodeJS instruction to install Angular-Cli

Now the Angular-Cli is available as the command ng. An integrated help message can be displayed with

1 npm --help

Listing 2.7: Angular-Cli help message

To create the new project, the command

1 ng new SaWebApp

Listing 2.8: Create new Angular project

has to be issued. This will create a new directory with a template for the new Angular application.All further commands have to be issues in the directory SaWebApp created by the Angular-Cli. Thecommand will also automatically run the NodeJS instruction npm install in the directory to installall required NodeJS dependencies of Angular. The created template can already be run as an application.When the command

1 ng serve

Listing 2.9: Start the embedded Angular-Cli Web server

is issued in the SaWebApp directory, Angular-Cli will automatically start a web sever. The template canthan be viewed in a web browser at the URL http://localhost:4200/. Starting the web servercan fail if the command is not run it with super user rights. Re-try as super user if this is the case. It ispossible to change the interface and port the web server is listening on by issuing the command

1 ng serve --host 0.0.0.0 --port 4200

Listing 2.10: Start the embedded Angular-Cli web server listening on a specified interface and port

where an IP of 0.0.0.0 means that the server listens on all interfaces. The embedded web serveroperates in a so called watch mode. This means, that if any of the HTML oder JavaScript files are changed,the web server will detect the changes automatically and update the browser view accordingly.

Once the development is finished, Angular-Cli can compose a compressed and uglyfied version ofthe HTML and JavaScript code. The final version of the complete SaWebApp can use the HTML andJavaScript files generated by this process. The Angular-Cli build command is

1 ng build

Listing 2.11: Angular-Cli command to build the application

and with the additional option

1 ng build --prod

Listing 2.12: Angular-Cli command to build the application to generate minified, uglifyed, and tree-shakedHTML and JavaScript

the build process includes also uglifying and tree-shakeing. Tree-shaking means that all unused codefrom the included libraries is left out of the final script files. The resulting files from the build process arelocated in the dist directory. Some of these files will have a random hexadecimal number as part oftheir name. This number is randomly generated by the build process and ensures that browsers reload thenew file and do not use an old, potentially outdated version from in their cache. The implementation ofthe Angular application is continued in the Section 3.3.

2.3 Final Project Architecture

The target architecture depicted in Figure 2.2 follows a client-server principle. The client is fully runwithin a web browser. Angular provides support to simplify the communication with the server, take care

9

of user inputs, and render data from the server.Looking on the server side, Dropwizard and all the Java libraries it provides lay a very good platform forthe Java code implementing the business logic. Java components to connect to databases or other webservices are also provided by Dropwizard.

Figure 2.2: Desired Client-Server Architecture

2.3.1 Java Application

In this section the parts of the Java web application will be enumerated. Figure 2.3 shows the describedstructure in full. The pom.xml-file was already discussed in the previous section. The other files orfolders will be explained here.

src->main->java Contains all Java code. See Section 3.1

src->main->resources->assets Contains all HTML and JavaScript as it was generated byAngular-Cli. See Section 3.3

target Output directory where Maven will place the files it build. In here the final fat-jar will be placed.

config.yml Configuration file for the web app. See Section 3.2

pom.xml The Maven configuration file as given in Listing 2.4

2.3.2 Angular Application

Angular-Cli generates the directories and files required for the project. This structure is shown inFigure 2.4 and is similar to other NodeJS projects. All further commands have to be issues in thedirectory SaWebApp created by the Angular-Cli. The Angular commonly uses TypeScript10 instead of ofJavaScript. TypeSript is a syntactical superset of JavaScript and is compiled into ordinary JavaScript by

10https://www.typescriptlang.org/

10

Figure 2.3: Full Java project structure

the Angular build tool. This process offers the possibilities to detect syntactical issues without running theJavaScript is a browser and hence accelerates the development. All compilation errors are show by ngserve.Angular follows a modular structure to split up an application. The most important parts are

Modules All Angular Applications are structured in modules. The application itself is always calledAppModule and describes all the modules making up this application.

Directives are parts which alter the DOM of the web page. I. e. directives are responsible to show andchange the content of the web page.

Components are the most used type of directives. Components consist of a TypeScript component and aHTML template. The HTML template defines how the web page (or parts of it) should look like.The TypeScript component holds the logic about how to fill the template with data, get user inputsfrom the template, how to modify the data, and how to communicate with other parts of the Angularapplication.

Services do the heavy lifting in the logic. While it would be possible to do all the work also in theTypeScript component, it should be rather done in a service.

TypeScript Classes are used to model data and logic as in any other object oriented programminglanguage. In principle also services are just TypeScript classes.

All of this parts are put into files inside the directory structure created by Angular-Cli. The directorystructure is shown shown in Figure 2.4 and has the following important directories and files

11

e2e Directory containing end to end tests. No end to end tests are defined in this example application.

node_modules all NodeJS dependencies are put into this directory. This directory can get quit big. Itis not required to transfer the content of this directory to an other machine. Instead, the content ofthe directory can be fetched with the NodeJS command

1 npm install

Listing 2.13: Install all dependencies

issued in the top directory SaWebApp.

dist The build process will write the resulting files into this directory. If this directory is not there yet,it will be automatically created by the build process.

scr This directory holds the source files for the Angular application. Most of the editing and developmentwork will be done in here.

The remaining files in the top directory SaWebApp hold the configuration for the overall project andvarious development services (e. g. GIT ignore config)

The next thing is the creation of the missing parts of the Angular application. The files for these partsare also created by Angular-Cli, which automatically links the created parts with the rest of the applicationby making the necessary entries in the project files. The first thing is to create the only component of theAngular application with

1 ng generate component SaMain

Listing 2.14: Create component SaMain

This will be the only component used in the application but others can be added in a similar manner. Theinstruction automatically generates the HTML and the Typescript part of the component. Next, the servicecan be created with

1 ng generate service SaHttp --module=app

Listing 2.15: Create service SaHttp in the main module

which generated the service as part of the main module. This will be the only service in this application,but other service can be created similarly. Lastly, two TypeScript classes are created with

1 ng generate class Request

Listing 2.16: Create the Request TypeScript class

and

1 ng generate class Response

Listing 2.17: Create the Request TypeScript class

More TypeScript classes can be created if needed.It is possible that the application misses some dependencies after the parts are generated. The missing de-pendencies can be installed with command shown in Listing 2.13 issued in the top directory SaWebbApp.In the end the files inside the scr->app should look like in Figure 2.5.

12

Figure 2.4: Initial Angular directory and file structure

13

Figure 2.5: Full Angular directory and file structure after the creation of all components, services, andclasses.

14

3

Application

This chapter goes over all Java and Angular files that have to be altered or created which are not explainedso far and lists their content.

3.1 Java

This section covers all Java classed needed to create the server side part of the application.

3.1.1 WebApplication.java

WebApplication.java is the main class of the project. This class describes what parts of the webapplication consist of and how these parts work together.

1 package at.tugraz.isds.sawebapp;23 import at.tugraz.isds.sawebapp.model.WebConfiguration;4 import io.dropwizard.Application;5 import io.dropwizard.assets.AssetsBundle;6 import io.dropwizard.bundles.redirect.PathRedirect;7 import io.dropwizard.bundles.redirect.RedirectBundle;8 import io.dropwizard.jersey.setup.JerseyEnvironment;9 import io.dropwizard.setup.Bootstrap;

10 import io.dropwizard.setup.Environment;1112 /**13 * Software Architecture Web Application - Tutorial14 *15 * Simple Dropwizard web application providing a client-side static HTML page16 * and a server-side java servlet.17 *18 * See http://www.dropwizard.io/1.2.0/docs/getting-started.html for more19 * information.20 *21 * <p><em>Date:</em>2017-11-22</p>22 * @author <a href="mailto:[email protected]">Heimo Gursch</a>23 */24 public class WebApplication extends Application<WebConfiguration> {2526 /**27 * Initialises the application.28 *29 * Creates a static assets bundle for delivering static content from within30 * the Dropwizard app jar file.31 *32 * @param bootstrap Configuration as it is read from the YAML-configuration33 * file

15

34 */35 @Override36 public void initialize(Bootstrap<WebConfiguration> bootstrap) {37 super.initialize( bootstrap );38 // Serv static assets via the root path39 bootstrap.addBundle(new AssetsBundle("/assets", "/"));40 // Redirect users to the index.html file if they did not specify a41 // particular file42 bootstrap.addBundle( new RedirectBundle( new PathRedirect("/", "/index.html") )

);43 }4445 /**46 * Setup for the main part of the Dropwizard web application.47 *48 * Creates the servlet (=resource) and puts it into service.49 *50 * @param configuration The configuration as read from the51 * YAML-configuration file52 * @param environment All services and configurations Dropwizard offers to53 * this application54 * @throws Exception Thrown if something goes wrong. Not used so far...55 */56 @Override57 public void run(WebConfiguration configuration, Environment environment) throws

Exception {58 // Create Servlet59 WebResource webResource = new WebResource(configuration.fromYaml);6061 // Add servelet62 JerseyEnvironment jersey = environment.jersey();63 jersey.register(webResource);64 }6566 /**67 * Main method to start the Dropwizard application.68 *69 * @param args Dropwizard needs the path to the YAML configuration file as70 * parameters. Run the application with parameter:71 * {@code server <path-to-config-file>/<config-file-name>.yml}72 * @throws java.lang.Exception Something when wrong wile starting the73 * Dropwizard application.74 */75 public static void main(String[] args) throws Exception {76 new WebApplication().run(args);77 }7879 }

Listing 3.1: WebApplication.java

3.1.2 WebResource.java

The class WebResource is the only servlet in this application. It does the actual work, i. e. it answerersthe requests from the web clients. Observe the use of the WebApplicationException to acknow-ledge an invalid request. The Servlet container handles this exception and sends the corresponding HTTPstatus code to the client.

1 package at.tugraz.isds.sawebapp;23 import at.tugraz.isds.sawebapp.model.Request;4 import at.tugraz.isds.sawebapp.model.Request.Operation;5 import at.tugraz.isds.sawebapp.model.Response;

16

6 import javax.inject.Singleton;7 import javax.ws.rs.Consumes;8 import javax.ws.rs.DefaultValue;9 import javax.ws.rs.GET;

10 import javax.ws.rs.POST;11 import javax.ws.rs.Path;12 import javax.ws.rs.Produces;13 import javax.ws.rs.QueryParam;14 import javax.ws.rs.WebApplicationException;15 import javax.ws.rs.core.MediaType;16 import javax.ws.rs.core.Response.Status;171819 /**20 * Simple servlet providing three methods:21 * <br><ul>22 * <li> {@link #calculate(at.tugraz.isds.sawebapp.model.Request)}: subtract,23 * multiply or divide two numbers.24 * <li> {@link #operations()} array of all operations supported by the25 * {@link #calculate(at.tugraz.isds.sawebapp.model.Request)} method.26 * <li> {@link #echo(java.lang.String)} a string with an appended27 * {@code helloString}-parameter28 * </ul>29 * <br>30 * <ul>31 * <li> The {@code @Path}-annotation tells the container the URL-extension of32 * this servlet.33 * <li> The {@code @Singleton}-annotation tells the container to instantiate34 * this servlet only once.35 * </ul>36 *37 * <p>38 * Content-type specification with {@code @Produces} and {@code @Consumes} can39 * be done for the class, or for each method separately. It tells the container40 * which content type a is generated and expected.41 * </p>42 *43 * <p><em>Date:</em>2017-11-22</p>44 * @author <a href="mailto:[email protected]">Heimo Gursch</a>45 */46 @Path("/resource")47 @Singleton48 public class WebResource{49 /**50 * Configured String51 */52 private final String helloString;5354 /**55 * Creates new instance and sets the helloString56 *57 * @param helloString The String this servelt will use for the greeting its58 * visitors.59 */60 public WebResource( String helloString ){61 this.helloString = helloString;62 }6364 /**65 * Simple echo method66 *67 * @param text String to be the prefix of the response68 * @return the sent text appended with hello-Sting

17

69 */70 @GET71 @Path("echo")72 @Produces(MediaType.TEXT_PLAIN)73 public String echo( @DefaultValue("default text") @QueryParam("text") String text

){74 return text+helloString;75 }7677 /**78 * Returns an array of all supported operations79 *80 * @return array of all supported operations81 */82 @GET83 @Path("operations")84 @Produces(MediaType.APPLICATION_JSON)85 public Operation[] operations(){86 return Operation.values();87 }8889 /**90 * Method to add, subtract, multiply or divide two numbers.91 *92 * The {@code @POST}-annotation specifies the HTTP method to call this93 * implementation The {@code @Path}-annotation tells the container the94 * URL-extension of this method95 *96 * This method uses a {@link WebApplicationException} to acknowledge an97 * invalid request. The Servlet container handles this exception and sends98 * the corresponding HTTP status code to the client.99 *

100 * @param request Input numbers and operation. Send to this method in the101 * body of a HTTP POST request102 * @return The calculation result.103 */104 @POST105 @Path("calculate")106 @Produces(MediaType.APPLICATION_JSON)107 @Consumes(MediaType.APPLICATION_JSON)108 public Response calculate( Request request ){109 Response response = new Response();110 switch( request.operation ){111 case Add:112 response.result = request.first+request.second;113 return response;114 case Subtract:115 response.result = request.first-request.second;116 return response;117 case Multiply:118 response.result = request.first*request.second;119 return response;120 case Divide:121 response.result = request.first/request.second;122 return response;123 default:124 throw new WebApplicationException("Unknown operation \""+request.operation+"

\"", Status.BAD_REQUEST );125 }126 }127 }

Listing 3.2: WebResource.java

18

3.1.3 Request.java

Class holding the values send form the JavaScript to the server.

1 package at.tugraz.isds.sawebapp.model;234 /**5 * Holds the input parameters for the calculation6 *7 * Since this class is only used for communication and no logic is done here8 * (not even value verification) all fields are public and no getter and setter9 * are used.

10 *11 * <p><em>Date:</em>2017-11-22</p>12 * @author <a href="mailto:[email protected]">Heimo Gursch</a>13 */14 public class Request{15 public static enum Operation { Add, Subtract, Multiply, Divide };1617 public double first;18 public double second;19 public Operation operation;20 }

Listing 3.3: Request.java

3.1.4 Response.java

Class holding the servers response to the clients request.

1 package at.tugraz.isds.sawebapp.model;234 /**5 * Hold the result of the calculation6 *7 * Since this class is only used for communication and no logic is done here8 * (not even value verification) all fields are public and no getter and setter9 * are used.

10 *11 * <p><em>Date:</em>2017-11-22</p>12 * @author <a href="mailto:[email protected]">Heimo Gursch</a>13 */14 public class Response{15 public double result;16 }

Listing 3.4: Response.java

3.1.5 WebConfiguration.java

This class extends the web Dropwizard configuration class. All properties defined in this class are readfrom the configuration file at the start of the server (see also Section 3.2).

1 package at.tugraz.isds.sawebapp.model;23 import com.fasterxml.jackson.annotation.JsonProperty;4 import io.dropwizard.Configuration;5 import javax.validation.Valid;6 import javax.validation.constraints.NotNull;78

19

9 /**10 * Configuration class to read in configuration parameter11 *12 * Since this class is only used for communication and no logic is done here13 * (value verification is done by annotations) all fields are public and no14 * getter and setter are used.15 *16 * <p><em>Date:</em>2017-11-22</p>17 * @author <a href="mailto:[email protected]">Heimo Gursch</a>18 */19 public class WebConfiguration extends Configuration{20 /**21 * Annotations are used to verify the parsed configuration22 */23 @Valid24 @NotNull25 @JsonProperty26 public String fromYaml;27 }

Listing 3.5: WebConfiguration.java

3.2 Configuration

The configuration file is written in the YAML-format. The configuration parameters are made up ofDropwizard specific configurations and of the configuration properties specified in the project specificconfiguration. The project specific configuration is defined in the WebConfiguration-class fromListing 3.6. The only required configuration form Dropwizard are the port and root path definitions, whichare stated in the lines 2-13 of Listing 3.6. The root path is used for all the servlets (i. e. DropwizardResource classes) but not for the static files (i. e. HTML and JavaScript) also served by Dropwizard.

1 # Configure ports an paths of Dropwizard server2 server:3 # Application port, i.e. used by the user4 applicationConnectors:5 - type: http6 port: 80807 # Specify the URL prefix for servlets (=resources)8 rootPath: "/api/*"9

10 # Housekeeping port, i.e. used to check statistics11 adminConnectors:12 - type: http13 port: 80811415 # Application specific settings16 fromYaml: "This is the config String"

Listing 3.6: config.yml

3.3 HTML and TypeScript

This section holds listings of the HTML and TypeScript files of the Angular application. In this sectiononly files having to be modified to create the application are listed. Every file which is completelygenerated by Angular-Cli and does not need to be touched is not listed here. All files listed here are in thescr->app and the scr->app->sa-main directories.

20

3.3.1 app.module.ts

app.module.ts is the main module file describing the top level components of the Angular application

1 // Main module file describing the Angular application2 //3 // standard Angular imports - provided by the setup4 import { BrowserModule } from ’@angular/platform-browser’;5 import { NgModule } from ’@angular/core’;67 // use HTTP communication8 import { HttpClientModule } from ’@angular/common/http’;9 // use input forms

10 import { FormsModule } from ’@angular/forms’;1112 // imports for own components - provided by Angular-CLi when creating the other13 // components14 import { AppComponent } from ’./app.component’;15 import { SaMainComponent } from ’./sa-main/sa-main.component’;16 import { SaHttpService } from ’./sa-http.service’171819 @NgModule({20 // definition of application components21 declarations: [22 AppComponent,23 SaMainComponent24 ],25 // modules used in this application26 imports: [27 BrowserModule,28 FormsModule,29 HttpClientModule30 ],31 // service usable for other modules32 providers: [SaHttpService],33 // main application component, i.e. entry point for Angular application34 bootstrap: [AppComponent]35 })36 export class AppModule { }

Listing 3.7: app.module.ts

3.3.2 app.component.html

This is the main HTML page, i.e. the entry point for the application. It makes up the main componenttogether with app.component.ts described in Section 3.3.3

1 <!-- Main HTML page holding a title and the only component -->2 <h1>{{title}}</h1>3 <app-sa-main></app-sa-main>

Listing 3.8: app.component.html

3.3.3 app.component.ts

This is the main TypeScripte file. It makes up the main component together with app.component.htmldescribed in Section 3.3.2

1 // describes the main component2 import { Component } from ’@angular/core’;34 @Component({

21

5 selector: ’app-root’,6 templateUrl: ’./app.component.html’,7 styleUrls: [’./app.component.css’]8 })9 export class AppComponent {

10 // set custom title of the app11 title = ’Software Architecture Web App’;12 }

Listing 3.9: app.component.ts

3.3.4 sa-http.service.spec.ts

Specification the the SaHttpService. It has to be checked that the Angular-Cli correctly generates theservice with the name SaHttpService and not SaHttpServiceService. If the name has to bechanged, it must also be changed in the app.module.ts-file shown in Section 3.3.1. The service itselfis shown in Section 3.3.5.

1 // specification of the SaHttpService2 import { TestBed, inject } from ’@angular/core/testing’;34 import { SaHttpService } from ’./sa-http.service’;56 describe(’SaHttpService’, () => {7 beforeEach(() => {8 TestBed.configureTestingModule({9 providers: [SaHttpService]

10 });11 });1213 it(’should be created’, inject([SaHttpService], (service: SaHttpService) => {14 expect(service).toBeTruthy();15 }));16 });

Listing 3.10: sa-http.service.spec.ts

3.3.5 sa-http.service.ts

This is the service doing all the communication with the server as outlined by its definition in Section 3.3.4.Special care has to be taken by the request URLs entered in line 32, 43, and 56. The relative URLsas shown here only work when the Java and the HTML/JavaScript server are operation on the sameIP address and port, i. e. when they is only one server for both. This configuration is intended for thefinal version all running on Dropwizard. During the development phase is is most likely the case, thatDropwizard and the Angular-Cli server are operated simultaneously and therefore other links are requiredhere. There are different possibilities to solve this problem.

• Instruct Angular-Cli to forward the requests to Dropwizard

• Mock the Dropwizard responses with Angular-Cli

• Change the URLs in line line 32, 43, and 56 to direct the requests at the URL of the Dropwizardserver. In this case the URLs would get the prefix of http://<IP-address>:<port> put infront.

In the case that Dropwizard and the Angular-Cli server are running on different ports or even differentIPs, a normal web browser will detect cross side scripting and block all requests. The so called sameorigin policy is responsible for that. This behaviour can be deactivated in most browsers, and has to bedeactivated to test such a setup. For the Google Chrome browser there is the Enable cross-origin resource

22

sharing plugin1 and for Mozilla Firefox there is the CORS Everywhere plugin 2, both offer easy ways totemporarily disable the same origin policy.

1 // Service communication over HTTP with the server2 import { Injectable } from ’@angular/core’;3 import { HttpClient, HttpHeaders, HttpParams } from ’@angular/common/http’;4 import { Observable } from ’rxjs/Observable’;5 import { of } from ’rxjs/observable/of’;6 import { catchError } from ’rxjs/operators’;7 import { Request } from ’./Request’;8 import { Response } from ’./Response’;9

10 // HTTP option setting the content type to JSON11 const httpOptions = {12 headers: new HttpHeaders({ ’Content-Type’: ’application/json’ })13 };141516 @Injectable()17 export class SaHttpService {1819 constructor( private http: HttpClient) { }2021 /**22 * Calls the echo method on the server. Returns the string the server send23 * back.24 * @param textInput - simple string, no JSON required25 */26 echo(textInput: string): Observable<string>{27 // HttpParams is immutable, hence set generates new object28 let params = new HttpParams().set("string", textInput);2930 // Executes the call. Caution the connection URL needs to be changed if this31 // runs with ng server. This string is for the final deployment only.32 return this.http.get(’/api/resource/echo’, { params: params, responseType: ’text

’ })33 .pipe( catchError(this.handleError<string>(’echo error - Did you use the

correct URL in the service?’)) );34 }3536 /**37 * Calls the operations method on the server. Returns the supported operations38 * from the server.39 */40 operations(): Observable<string[]> {41 // Executes the call. Caution the connection URL needs to be changed if this42 // runs with ng server. This string is for the final deployment only.43 return this.http.get<string[]>(’/api/resource/operations’)44 .pipe( catchError(this.handleError<string[]>(’operations error - Did you use

the correct URL in the service?’, [])) );45 }4647 /**48 * Calls the calculate method on the server and returns the result of the49 * calculation.50 *51 * @param calculation request for the server52 */53 calculate(request: Request): Observable<Response> {54 // Executes the call. Caution the connection URL needs to be changed if this

1https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi/

2https://addons.mozilla.org/de/firefox/addon/cors-everywhere/

23

55 // runs with ng server. This string is for the final deployment only.56 return this.http.post<Response>(’/api/resource/calculate’, request, httpOptions)57 .pipe( catchError(this.handleError<Response>(’calculate error - Did you use

the correct URL in the service?’)) );58 }5960 /**61 * Handle Http operation that failed.62 * Let the app continue.63 * @param operation - name of the operation that failed64 * @param result - optional value to return as the observable result65 */66 private handleError<T> (operation = ’operation’, result?: T) {67 return (error: any): Observable<T> => {68 // Log for the user69 alert( operation );70 // log for the71 console.log( error );7273 // Let the app keep running by returning an empty result.74 return of(result as T);75 };76 }7778 }

Listing 3.11: sa-http.service.ts

3.3.6 request.ts

This TypeScript defines an object holding all the parameters of a calculation request.

1 // simple object holding all parameters of a calculation request2 export class Request {3 first: number;4 second: number;5 operation: string;67 constructor(values: Object = {}) {8 Object.assign(this, values);9 }

10 }

Listing 3.12: request.ts

3.3.7 response.ts

This TypeScript defines an object holding response of a calculation.

1 // simple object holding the result of an calculation2 export class Response {3 result: number;45 constructor(values: Object = {}) {6 Object.assign(this, values);7 }8 }

Listing 3.13: response.ts

24

3.3.8 sa-main.component.html

This is the HTML part of the SaMain component. It makes up the component together with thesa-main.component.ts described in Section 3.3.9.

1 <!-- Simple HTML component -->2 <div>3 <div>4 <label>Input: </label>5 <!-- Create an input-field and establish the two-way binding with the6 Angular object -->7 <input type="text" [(ngModel)]="textInput">8 <!-- Create a button and bind the click action to a call of the echo()9 method -->

10 <button (click)="echo()">echo</button>11 </div>12 <hr>13 <div>14 <label>first number: </label>15 <!-- Create an input-field and establish the two-way binding with the16 Angular object -->17 <input type="number" step=’0.1’ [(ngModel)]="request.first">18 </div>19 <div>20 <label>second number: </label>21 <!-- Create an input-field and establish the two-way binding with the22 Angular object -->23 <input type="number" step=’0.1’ [(ngModel)]="request.second">24 </div>25 <div>26 <label>result: </label>27 <!-- Bind the result of the computation to the element. Show the element28 only if there is a result -->29 <span *ngIf="response.result" [innerText]="response.result"></span>30 </div>31 <div>32 <label>action: </label>33 <!-- Establish a two-way binding between the selected element and the34 Angular object. -->35 <select [(ngModel)]="request.operation">36 <!-- create an entry in the selection box for each entry in the operations37 array -->38 <option [ngValue]="i" *ngFor="let i of operations">{{i}}</option>39 </select>40 <!-- Create a button and bind the click action to a call of the echo()41 method -->42 <button (click)="calculate()">calculate</button>43 </div>44 </div>

Listing 3.14: sa-main.component.html

3.3.9 sa-main.component.ts

This is the TypeScript part of the SaMain component. It makes up the component together with thesa-main.component.html described in Section 3.14. It connects the HTML vies of this componentssa-main.component.html described in Section 3.3.8 with the service sa-http-service.tsdescribed in Section 3.3.5.

1 // TypeScript connecting the SaMain component with the SaHttpService2 import { Component, OnInit } from ’@angular/core’;3 import { Request } from ’../Request’;4 import { Response } from ’../Response’;

25

5 import { SaHttpService } from ’../sa-http.service’;67 @Component({8 selector: ’app-sa-main’,9 templateUrl: ’./sa-main.component.html’,

10 styleUrls: [’./sa-main.component.css’]11 })12 export class SaMainComponent implements OnInit {13 // Create the objects holding the data of this component14 textInput: string = ’hello’;15 request: Request = new Request({first: 2.3, second: 3.4 });16 response: Response = new Response();17 operations: string[];1819 constructor(private saHttpService: SaHttpService) { }2021 /**22 * Get all available operations from the service when the component is first23 * initialised. Set the first of the retrieved components as the selected24 * option.25 */26 ngOnInit() {27 this.saHttpService.operations().subscribe( operations => {28 this.operations = operations;29 this.request.operation = operations[0];30 });31 }3233 /**34 * Execute the echo request and write the response back.35 */36 echo(){37 this.saHttpService.echo( this.textInput ).subscribe( textOutput => {38 this.textInput = textOutput;39 });40 }4142 /**43 * Execute the echo request and write the response back.44 */45 calculate(){46 this.saHttpService.calculate( this.request ).subscribe( response => {47 this.response = response;48 });49 }5051 }

Listing 3.15: sa-main.component.ts

26

4

Compiling and running the complete application

First the Angular application needs to be build. The resulting files from the dist directory than have tobe copied into the src->main->resources->assets directory of the Java application.The Java application can than be build with Maven, either via the command line or through the IDE.When the project is run or build the first time, Maven needs to download all dependencies. This can take awhile. Also the building process can take a while, since the creation of the fat-jar might be complicatedfor Maven. If the Java project has been build, it can started it with the parameters

1 server config.yml

Listing 4.1: Running the project

The parameters shown in Listing 4.1 are needed to tell Dropwizard that it should be run in its server modeand that the file config.yml contains the configuration for the server.

If the fat-jar is used to run the server, the web application can be started with

1 java - jar SaWebApp.jar server config.yml

Listing 4.2: Running the jar

When the web application is up and running, logging information will be displayed in the console.The resulting web page can be seen under the URL redirected URL http://localhost:8080/ orthe full http://localhost:8080/index.html. The http://localhost:8081 presents apage with some small statistic about the running Dropwizard service.

27

List of Figures

2.1 Basic Maven Directory Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.2 Desired Client-Server Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102.3 Full Java project structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.4 Initial Angular directory and file structure . . . . . . . . . . . . . . . . . . . . . . . . . . . 132.5 Full Angular directory and file structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

28

Listings

2.1 Maven command line instructions to create the project . . . . . . . . . . . . . . . . . . 52.2 Maven command line instructions to compile the project . . . . . . . . . . . . . . . . . 52.3 Maven command line instructions to build and package the project . . . . . . . . . . . . 52.4 Content of the pom.xml file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62.5 NodeJS instruction to update all packages . . . . . . . . . . . . . . . . . . . . . . . . . 82.6 NodeJS instruction to install Angular-Cli . . . . . . . . . . . . . . . . . . . . . . . . . . 92.7 Angular-Cli help message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.8 Create new Angular project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.9 Start the embedded Angular-Cli Web server . . . . . . . . . . . . . . . . . . . . . . . . 92.10 Start the embedded Angular-Cli web server listening on a specified interface and port . . 92.11 Angular-Cli command to build the application . . . . . . . . . . . . . . . . . . . . . . . 92.12 Angular-Cli command to build the application to generate minified, uglifyed, and tree-

shaked HTML and JavaScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.13 Install all dependencies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.14 Create component SaMain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.15 Create service SaHttp in the main module . . . . . . . . . . . . . . . . . . . . . . . . 122.16 Create the Request TypeScript class . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.17 Create the Request TypeScript class . . . . . . . . . . . . . . . . . . . . . . . . . . . 123.1 WebApplication.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.2 WebResource.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.3 Request.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.4 Response.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.5 WebConfiguration.java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193.6 config.yml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203.7 app.module.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.8 app.component.html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.9 app.component.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213.10 sa-http.service.spec.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223.11 sa-http.service.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233.12 request.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243.13 response.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243.14 sa-main.component.html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253.15 sa-main.component.ts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254.1 Running the project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274.2 Running the jar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

29