<?xml version="1.0" encoding="UTF-8"?> <chapter version="5.1" xml:id="sd1Deploy" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xi="http://www.w3.org/2001/XInclude" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns="http://docbook.org/ns/transclusion" xmlns:m="http://www.w3.org/1998/Math/MathML" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:db="http://docbook.org/ns/docbook"> <title>Application deployment I</title> <section xml:id="sd1DeployPrepare"> <title>Preparations</title> <para>Read <link xlink:href="https://www.cs.swarthmore.edu/~newhall/unixhelp/debuggingtips_Java.html">http://www.cs.swarthmore.edu/~newhall/unixhelp/debuggingtips_Java.html</link> up to including the <quote>The <code>CLASSPATH</code> environment variable and JAR files</quote> section.</para> </section> <section xml:id="sda1DeployExercise"> <title>Exercises</title> <qandaset defaultlabel="qanda" xml:id="sd1QandaArrayVarious"> <title>Various integer array algorithms</title> <qandadiv> <qandaentry> <question> <para>The following Maven project contains a series of yet unimplemented methods and corresponding tests currently being excluded by an <interfacename xlink:href="https://junit.org/junit5/docs/current/api/org/junit/jupiter/api/Disabled.html">@Disabled</interfacename> annotation:</para> <annotation role="make"> <para role="eclipse">P/Sd1/Array/arraycalcExercise</para> </annotation> <programlisting language="java">... <emphasis role="bold">@Disabled // Remove me to enable testing your application</emphasis> @SuppressWarnings("javadoc") public class ArrayMethodTest { @Test public void testFindIndex(){ assertEquals(Arraymethods.findIndex(new int[]{1, 3, -3, 5}, -3), 2);...</programlisting> <para>Import this project for getting started. The following hints may help you completing the implementation</para> <glosslist> <glossentry> <glossterm><link xlink:href="P/Sd1/Array/arraycalcExercise/target/site/apidocs/de/hdm_stuttgart/mi/sd1/store/Arraymethods.html#swap-int:A-int:A-">swap</link></glossterm> <glossdef> <para>This effectively requires extending the concept of swapping just two integer values within a block</para> <programlisting language="java">int a = 3, b = 5; // Other code ... {// Swap values of a and b final int tmp = a; a = b; b = tmp; }</programlisting> </glossdef> </glossentry> <glossentry> <glossterm><link xlink:href="P/Sd1/Array/arraycalcExercise/target/site/apidocs/de/hdm_stuttgart/mi/sd1/store/Arraymethods.html#isPalindrome-java.lang.String-">isPalindrome</link></glossterm> <glossdef> <para>Consider a two step implementation:</para> <orderedlist> <listitem> <para>Normalize a given palindrome candidate by transforming to lower case and erasing non-letters:</para> <para><code>Hey, Roy! Am I mayor? Yeh!</code> --> <code>heyroyamimayoryeh</code></para> <para>You may search the <xref linkend="glo_API"/> of class <classname xlink:href="https://docs.oracle.com/javase/10/docs/api/java/lang/Character.html">Character</classname> assisting you to distinguish letters from non-letters.</para> </listitem> <listitem> <para>Check the remaining string for being a palindrome.</para> </listitem> </orderedlist> </glossdef> </glossentry> <glossentry> <glossterm><link xlink:href="P/Sd1/Array/arraycalcExercise/target/site/apidocs/de/hdm_stuttgart/mi/sd1/store/Arraymethods.html#containsSameElements-int:A-int:A-">containsSameElements</link></glossterm> <glossdef> <para>You may copy <code language="java">int[] b</code> array to a <quote>shadow</quote> array and then subsequently erase all elements of <code language="java">int[] a</code> from this copy. The method <link xlink:href="P/Sd1/Array/arraycalcExercise/target/site/apidocs/de/hdm_stuttgart/mi/sd1/store/Arraymethods.html#findIndex-int:A-int-">findIndex</link> is quite helpful.</para> <para>Consider for example <code language="java">int[] bCopy = {1, 3, 4, 3, 7}</code> containing 5 elements. Suppose our array <code language="java">a</code> contains the value 3 which exists at index position 1 in <code language="java">bCopy</code>. We may override the value index position 1 by the last array value 7 and thereby keeping track of reducing the number of array elements to 4 like {1, 7, 4, 3}.</para> <para>Off course the array <code language="java">bCopy</code> cannot shrink. But we may introduce an integer variable to account for the effective number of array elements still to be considered. If and only if all elements from <code language="java">a</code> are subsequently found within <code language="java">bCopy</code> the two arrays <code language="java">a</code> and <code language="java">b</code> are equal.</para> </glossdef> </glossentry> </glosslist> </question> <answer> <annotation role="make"> <para role="eclipse">P/Sd1/Array/arraycalcSolution</para> </annotation> </answer> </qandaentry> </qandadiv> </qandaset> </section> <section xml:id="sd1AppDeploy2Exercise"> <title>Part II, Exercises</title> <qandaset defaultlabel="qanda" xml:id="sd1QandaMedianCmdline"> <title>A command line version computing a sample's average and median</title> <qandadiv> <qandaentry> <question> <para>This exercise extends <xref linkend="sd1StoreStatistics"/> by adding a command line interface. Consider the following console execution:</para> <screen>goik >java -jar statistics-1.0.jar 2 6 7 Your sample's average is: 5.0 Your sample's median is: 6.0</screen> <para>The above example executes our Java program in a shell and supplies three command line parameters 2, 6 and 7. The program then executes and creates the desired statistical data.</para> <para>The subsequent remarks may assist you creating an implementation:</para> <orderedlist> <listitem xml:id="sd1OlMedianCmdLineStep1"> <para>Using command line values means entering strings rather then e.g. integer values: In the current example the Java runtime will pass an array of strings <code language="java">{"2", "6", "7"}</code> on behalf of the user's input <quote><code language="java">2 6 7</code></quote> to your <code language="java">main(String [] args)</code> method. These strings must be converted to integer values. This may be achieved by means of <methodname xlink:href="https://docs.oracle.com/javase/10/docs/api/java/lang/Integer.html#parseInt-java.lang.String-">parseInt(String)</methodname>.</para> <para>Depending on inconsistent user input like <quote><code language="java">three</code></quote> instead of <quote><code language="java">3</code></quote> you may decide to terminate your application thereby providing a meaningful error message:</para> <screen>goik >java -jar statistics-1.0.jar 1 2 three Input string 'three' does not represent an integer value</screen> </listitem> <listitem> <para>If the user does not provide any input at all our program shall terminate as well:</para> <screen>goik >java -jar statistics-1.0.jar No values provided</screen> </listitem> <listitem> <para>Provide an <classname>public enum ErrorState</classname> definition representing all three possible error states:</para> <glosslist> <glossentry> <glossterm><code>OK</code>:</glossterm> <glossdef> <para>No error, all user input strings represent integer values.</para> </glossdef> </glossentry> <glossentry> <glossterm><code>NO_VALUE</code>:</glossterm> <glossdef> <para>Error: No user input at all.</para> </glossdef> </glossentry> <glossentry> <glossterm><code>NO_INTEGER</code>:</glossterm> <glossdef> <para>Error: At least one input value does not represent an integer value.</para> </glossdef> </glossentry> </glosslist> </listitem> <listitem> <para>Implement a class <classname>InputValidator</classname> to validate user input and thereby converting string values to an integer array of equal size:</para> <programlisting language="java">/** * Validate sample input strings and convert * them to integer values. */ public class InputValidator { /** * Integer values being calculated upon * constructor call. */ public final int[] values; /** * Transform a series of strings into integer values. In case * of invalid input, a corresponding error messsage will be written * to System.err and the current application will terminate by calling * {@link System#exit(int)}. Example: The array ["-1", "20", "three"] * contains two valid elements and the invalid element "three" which * cannot be converted to an integer value by virtue of * {@link Integer#parseInt(String)}. * * @param userInput A set of strings possibly representing integer values. */ public InputValidator(final String[] userInput) {...} }</programlisting> <para>You may then create an instance by supplying your <code language="java">main(String[] args)</code> command line values:</para> <programlisting language="java">public static void main(String[] args) { final InputValidator userInput = new InputValidator(args); ...</programlisting> <para>Choose your implementation with testing in mind.</para> </listitem> <listitem> <para>Write at least one test case for all three possible error categories and check for correct behaviour of your <classname>InputValidator</classname> class.</para> </listitem> <listitem> <para>Use your class <classname xlink:href="P/Sd1/Array/integerStoreMedianAnswer/target/site/apidocs/de/hdm_stuttgart/mi/sd1/store/IntegerStore.html">IntegerStore</classname> from exercise <xref linkend="sd1StoreStatistics"/> to compute the desired output.</para> </listitem> <listitem> <para>Simulating command line arguments in <xref linkend="glo_Soft_Eclipse"/> requires a run time configuration. Click <guimenu>Run</guimenu> <guimenuitem>Run Configurations...</guimenuitem>. Choose <quote>Java Applications</quote> and "new launch configuration" from the panel's left side, choose your project and main class (if not already selected).</para> <screenshot> <info> <title>Defining an Eclipse runtime configuration</title> </info> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/runconfigSelectClass.png"/> </imageobject> </mediaobject> </screenshot> <para>Select the <guimenu>Arguments</guimenu> tab. Enter your desired command line values, hit <guibutton>Apply</guibutton> and subsequently <guibutton>Run</guibutton> to launch your application.</para> <screenshot> <info> <title>Defining an Eclipse runtime configuration</title> </info> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/runconfigDefineArgs.png"/> </imageobject> </mediaobject> </screenshot> </listitem> <listitem> <para>Maven projects allow for creation of executable jar archives. This leverages the process being described in <link xlink:href="http://www.skylit.com/javamethods/faqs/createjar.html">Creating an Executable jar File</link>. It avoids messing with manifest files and zipping up archives manually.</para> <para>Among several configuration possibilities you may use the <link xlink:href="https://maven.apache.org/plugins/maven-jar-plugin">Maven JAR Plugin</link> and its <option xlink:href="https://maven.apache.org/plugins/maven-jar-plugin/usage.html#How_to_build_a_JAR_file">package</option> goal. You have to add this plugin to the <tag class="starttag">plugins</tag> section of your <filename>pom.xml</filename> file. The plugin in turn requires defining the fully qualified name of your entry class <coref linkend="sd1CaPomFqnMainEntryClass"/> containing the desired <methodname>main(String[] args)</methodname> method:</para> <programlisting language="xml">... <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <javadocDestdir>~/tmp</javadocDestdir> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <emphasis role="bold"> <mainClass>de.hdm_stuttgart.mi.sd1.statistics.main.Statistics</mainClass> </emphasis> <co xml:id="sd1CaPomFqnMainEntryClass"/> </manifest> </archive> </configuration> </plugin> </plugins> </build> ...</programlisting> <para>Creating the actual jar archive may be triggered by either of:</para> <glosslist> <glossentry> <glossterm>From the command line:</glossterm> <glossdef> <para>Change to your project root containing your <filename>pom.xml</filename> file and execute <command>mvn</command> <option>package</option>.</para> </glossdef> </glossentry> <glossentry> <glossterm>From inside <xref linkend="glo_Soft_Eclipse"/>:</glossterm> <glossdef> <para>Create a maven run time configuration (see above) containing your <option>package</option> goal:</para> <screenshot> <info> <title>Creating a Maven runtime configuration corresponding to the <option>package</option> goal</title> </info> <mediaobject> <imageobject> <imagedata fileref="Ref/Fig/runconfigMavenGoalPackage.png"/> </imageobject> </mediaobject> </screenshot> </glossdef> </glossentry> </glosslist> <para>After creating the jar archive you may now run your program in a shell as being described in <xref linkend="sd1OlMedianCmdLineStep1"/> of this section.</para> </listitem> </orderedlist> </question> <answer> <annotation role="make"> <para role="eclipse">P/Sd1/Array/medianCmdLine</para> </annotation> </answer> </qandaentry> </qandadiv> </qandaset> </section> </chapter>