Skip to content

Lab 08

In this lab session you will be training advanced build system concepts, such as build lifcycle phases, artifact sideloading, and accessing third party artifact repositories.
You will be working with the XoxInternals code, which is a full working Model & Controller implementation the TicTacToe game (paraphrased as Xox, for the X's and the O's).
To clone the sources, use: git clone https://github.com/m5c/XoxInternals.git

Maven lifecycle

Maven has three built-in lifecycles, each consisting of phases. We're mostly interested in the default lifecycle, which allows building software from sources.

Build by calling lifecycle phases

  • The maven command always expects a lifecycle phase as argument.
  • For every phase provided, the entire lifecycle until that phase is executed.
  • E.g. mvn package command will execute all default lifecycle phases until (and including) the package phase.

Your turn

  • You will be working with a new project XoxFrontend, which will call some of the functionality provided by the cloned XoxInternals project.
    • However it is important that we want to connect these two projects, using maven, NOT by copy-pasting code from one project to the other.
  • For a start, initialize a new repo, called XoxFrontend, by using the maven archetype command:

    mvn archetype:generate \
    -DgroupId=ca.uqam.info \
    -DartifactId=XoxFrontend \
    -DarchetypeArtifactId=maven-archetype-quickstart \
    -DinteractiveMode=false
    

    If you're on windows, type the command in a single line, and omit the antislashes.

  • The command will produce a new maven project of the following structure:

    XoxFrontend/
    ├── pom.xml
    └── src
        ├── main
           └── java
               └── ca
                   └── uqam
                       └── info
                           └── App.java
        └── test
            └── java
                └── ca
                    └── uqam
                        └── info
                            └── AppTest.java
    
    12 directories, 3 files
    

  • Next build the project. Do so by calling the maven default lifecycle phase that only translates all java files into class files, without producing a jar.
    • Inspect the target folder. Verify there are class files, but no jar file.
  • Build the project, by calling the maven default lifecycle phase that does the same as before, but also produces a jar file.
    • Inspect the target folder. Verify there are class files, and a jar file.

Vulnerability scans

  • Every project dependency is a potential liability. Whatever vulnerability is included in one of your dependencies, is potentially also a security risk for your own project.
  • Luckily pom.xml files are an explicit form of declaring dependencies, that is, by inspecting the pom.xml potential vulnerabilities are easily detectable.
  • Searching (and fixing) vulnerable dependencies known as vulnerability scans.

IntelliJs vulnerability plugin

  • Intellij has by-default-activated plugin named: Package Checker
  • In class, you've seen a short demo of how to use the tool.
    • When a pom.xml file is opened, vulnerable dependencies are hihglightes with a different background
    • Hovering over the highlighted zones shows additional information on the vulnerability cause (and how to fix it)

Your turn

  • Open your XoxFrontend project in IntelliJ.
    • Double-click the pom.xml file.
    • Carefully inspect the background colour of all lines. You'll see some lines highlighted by the Package Checker plugin.
    • Hover your mouse over a highlighted line. Wait a second, a popup will appear.
  • Carefully read the message, it will tell you how to fix the vulnerability that you currently have in your project.
  • Fix the vulnerability, and make sure your project can still be built.

Sideloading

  • Sideloading refers to "outsmarting" maven's dependency resolve algorithm by artificially injecting an artifact directly into the local .m2 respository.
  • This technique allows usage of dependencies that do not exist on the official online maven repository, and hence could not be automatically resolved by maven.
  • The trick relies on the fact that maven will never search for an artifact online, once it has been found in the local repo.

Example:

  • XoxFrontend will be needing functionality from the cloned XoxInternals project.
    • In this case XoxFrontend can declare a <dependency> in it's pom.xml file:
      <dependency>
          <groupId>ca.uqam</groupId>
          <artifactId>xoxinternals</artifactId>
          <version>1.7</version>
      </dependency>
      
    • If we sideload XoxInternals into the local .m2 cache, the dependency is directly:
      • Maven does not need to search on online server for the artifact (we injected it ourselves)
      • XoxFrontend can use the library code without code duplication.

There are different ways to sideload artifacts into the local .m2 repository cache.

Do not copy code!

Do not copy past code from the cloned XoxInternals project. The goal is to use code from XoxInternals as maven dependency, not by code duplication.

Sideloading from maven projects

  • The easiest form of sideloading occurs when the dependency in question is itself a maven project.
  • Luckily this is the case. XoxInternals has a pom.xml, and is itself a maven project.
  • In this case the install phase can be used, to not only build an artifact, but also sideload it into the local cache.

Your turn

  • Add the above dependency block to the XoxFrontend's pom.xml file.
    • It will show up red. The dependency cannot be resolved, because no such artifact is on the official maven servers.
  • Next: Inspect your local .m2 directory. It may be hidden on your system. If it is not visible in the file manager, open a terminal and access the hidden .m2 directory on your home folder.
    • Inspect the content, verify there is no artifact ca/uqam/info/xoxinternals
  • Build the previously cloned XoxInternals project using the install phase.
  • Inspect your local .m2 cache again. You should not see a new artifact in ca/uqam/info/xoxinternals.
  • Switch back to the XoxFrontend's pom.xml, the dependency should now no longer show red, but be correctly resolved.

Next we want to see if we can actually use the code from the correctly resolved dependency:

  • Add a new launcher to the XoxFrontend project that uses functionality from the XoxInternals project.
  • Use the below code, to initialize a new game instance between Alice and Bob:

    public class XoxAliceAndBob {
      public static void main(String[] args) {
        long gameId = XoxGameInitiator.createNewGame("Alice", "Bob");
        // Prints actions for alice.
        XoxBoardAndActionPrinter.printBoardAndActionsForPlayer(gameId, "Alice");
      }
    }
    
    For the two missing calls, you can use the below helper classes:

  • XoxGameInitiator.java:

    public class XoxGameInitiator {
      /**
       * Creates a new game instance for the given player names.
       *
       * @param playerName1 name of first player.
       * @param playerName2 name of second player.
       * @return long value of a unique game ID, that can be used to interact with game instance via
       * manager.
       */
      public static long createNewGame(String playerName1, String playerName2) {
        Player player1 = new Player(playerName1, "#0000FF");
        Player player2 = new Player(playerName2, "#00FF00");
        List<Player> playerList = new LinkedList<Player>();
        playerList.add(player1);
        playerList.add(player2);
        XoxInitSettings xoxSettings = new XoxInitSettings(playerList, playerName1);
        return XoxManagerImpl.getInstance().addGame(xoxSettings);
      }
    }
    

  • XoxBoardAndActionPrinter.java:
    public class XoxBoardAndActionPrinter {
    
      public static void printBoardAndActionsForPlayer(long gameId, String player) {
        System.out.println(XoxManagerImpl.getInstance().getBoard(gameId));
    
        // Print all possible actions for Alice
        XoxClaimFieldAction[] actions = XoxManagerImpl.getInstance().getActions(gameId, player);
        for (int i = 0; i < actions.length; i++) {
          System.out.println(actions[i]);
        }
      }
    }
    

Setup the maven exec plugin in your pom.xml and make sure you can compile and run your XoxFrontend with:
mvn clean compile exec:java

Sideloading from generic JAR files

  • Often the library you're missing is itself not provided as source code, but you have only a jar file.
  • Possibly the library is not even a maven project !
  • It is still possible to sideload just from a jar file, directly into the local .m2 repository cache.
  • In the last course, you've seen a maven command to do just that.

Your turn

  1. Build the XoxInternals project with mvn clean package
  2. Copy the jar file from the target directory to your Desktop.
  3. Delete the XoxInternals project from your hard drive, but keep the jar file.
  4. Delete the XoxInternals artifact from your local .m2 repository cache.

Clear you local repo!

The above steps are important. From the previous exercise you still have the XoxInternals artifact in your local repo.

At this point the XoxFrontend project will no longer work, because we've manually removed the XoxInternals projects it depends on.`

  1. Just using the saved jar file, use the mvn command seen in class to directly install an artifact from a jar file.
  2. Make sure to use the correct groupId, artifactId and version, so the dependency can be correctly resolved.
  3. Verify your local .m2 content and verify that you can now once more build and run the XoxFrontend application.

Third party repositories

Third party repositories are online folders providing unofficial maven artifacts. There are several reasons for placing artifacts in third party repos, notably access restriction and the ability to revoke.

Getting a dependency from a third party repo

  • Instead of sideloading the XoxInternals artifact manually, it is preferrably to retrieve the artifact from a non-official third-party repo.
  • Reminder, maven's resolving algorithm is:
  • First search to local cache for a match (local .m2 directory)
  • Only as fallback: search the third party repos (if defined)
  • Only as last resort: searches the official maven servers.
  • Sideloading targets the first step. Third party repos the second step.

In the next exercise you will be using a third party repository, instead of manually sideloading an artifact.

Your turn

  • Delete the sideloaded Xox artifact from your local ~/.m2/repository/ directory.

Clear you local repo!

The above steps are important. From the previous exercise you still have the XoxInternals artifact in your local repo. If you do not delete it, maven will stop after step 1 and never search for the artifact online.

  • Try to compile your XoxFrontend project. It will fail, because XoxInternals can no longer be resolved.
  • Access your XoxFrontend project's pom.xml and add a reference the inf2050 repo (which is a non-officiel 3rd party maven repo, created specifically for this course):
    <repositories>
        <repository>
            <id>Max's third party repo on a UQAM GitLab file server</id>
            <url>https://max.pages.info.uqam.ca/inf2050repo/</url>
        </repository>
    </repositories>
    
  • Compile your project again with: mvn clean test
  • Carefully inspect the output.
    • Find the output line that indicates the missing artifact has been downloaded from the third party server.
    • Verify the build was once more successful.
Why is there suddenly again a copy of XoxInternals in your local cache ?

Maven always caches artifacts locally, once they were successfully retrieved. Otherwise, you would never be able to work offline.

Build profiles

  • Build profiles allow you to develop different version of an application, by simply specifying a profile name along the standard maven command.
  • The syntax is -P (for profile), directly followed by the profile name.
    • Note there is no space between the -P switch and the profile name.
    • Example: mvn clean package -Ppremium-software-version

Alternative launchers

  • One use case of build profiles is the specification of alternative launchers.
  • This way different functionality of a software can be started, or different hard coded parameters can be used.

Your turn

  • Revise the build profile syntax presented in the last course and modify your XoxFrontend to contain two launcher classes:
    • For the first launcher, you can reuse the one you coded for Alice and Bob, earlier in this lab session.
    • A second launcher, to initialize a game between players Eve and Bob.
      public class XoxEveAndBob {
        public static void main(String[] args) {
          long gameId = XoxGameInitiator.createNewGame("Eve", "Bob");
          // prints nothing! Alice is not participating in match.
          XoxBoardAndActionPrinter.printBoardAndActionsForPlayer(gameId, "Alice");
        }
      }
      
  • Modify the XoxFrontend project's pom.xml, so two new build profiles are defined:
    • alice-and-bob as default profile.
    • eve-and-bob as alternative profile.
  • For each build profile, add a configuration of the exec plugin, make sure that:
    • The alice-and-bob profile launches the original XoxAliceAndBob java launcher class.
    • The eve-and-bob profile launches the newly created XoxEveAndBob java launcher class.
  • Build and launch both variants using either of:
    • mvn clean compile exec:java
    • mvn clean compile exec:java -Palice-and-bob
    • mvn clean compile exec:java -Peve-and-bob
  • Verify all commands print an empty board of the initialized game, but only the alice-and-bob / default profile additionally prints a list of player actions.