Categories
Java

Lokales Maven Repository

Aktuell migrieren wir eine Legacy Anwendung in eine neue Systemlandschaft und dabei wollen wir das Dependency Managment überarbeiten, das bisher aus einem Verzeichnis mit *.jar Library Dateien besteht, ohne Sourcecode. Wir wollen im Projekt Maven einführen. Das funktioniert überwiegend recht gut und einfach, indem wir die einzelnen *.jar Dateien durchgehen, die Versionsnummer bestmöglich raten und dann die entsprechende Abhängigkeit in die Maven Datei pom.xml hinzufügen. Die einzelnen Bibliotheken lassen sich gut über diese Seite finden: https://mvnrepository.com/

Allerdings gibt es auch firmeninterne oder propritäre Java Bibliotheken, diese lassen sich natürlich nicht über das zentrale Maven Repository finden.

Bei einem anderen Kunden haben wir zur Lösung dieses Problems einen eigenes, internes Repository aufgebaut: Sonatype Nexus. Dieses dient als Proxy für das öffentliche Maven Repository und zusätlich können hier die internen Bibliotheken hochgeladen und so verfügbar gemacht werden. Dieses Vorgehen kam bei dem aktuellen Projekt allerdings nicht in Betracht, so dass wir uns nach einer Alternative umgesehen haben. Das Dependency Managment nicht zu ändern wäre auch eine Alternative gewesen.

Die Alternative, die wir dann fanden, war das Einrichten eines im Projekt eingebetteten, lokalen Repositories. Die Idee dazu fanden wir in diesem Artikel: https://devcenter.heroku.com/articles/local-maven-dependencies

Das Vorgehen ist von der Idee her recht simpel: Im Projekt Ordner wird ein Ordner, zB maven/repository, angelegt und in diesem ein lokales Repository aufgebaut, welches dann in der pom.xml referenziert werden kann, um so von dort die internen Libraries verfügbar zu machen.

Repository anlegen

Im Projekt wird ein Verzeichnis für das lokale Repository angelegt, zB maven/repository.

Mittels des Maven deploy Befehls können dann die internen Libraries aus dem bisherigen Repository (aka WEB-INF/lib Folder) in das Maven Repository importiert werden.

Beispielsweise wird die firmeninterne companyLib.jar incl. Sourcecode in der Version ‘latest’, denn es gibt immer nur die letzte Version, installiert:

mvn deploy:deploy-file -Durl=file://C:/workspace/myLegacyProject/maven/repository/ -Dfile=companyLib-latest.jar -Dsources=companyLib-latest-sources.jar -DgroupId=de.deringo -DartifactId=companyLib -Dpackaging=jar -Dversion=latest

Das macht man dann für alle Libraries und kann anschließend das legacy Repository löschen.

Repository referenzieren

Das lokale Repository im Projekt wird wie folgt referenziert:

  <repositories>
    <repository>
      <id>project.local</id>
      <name>project</name>
      <url>file:${project.basedir}/maven/repository</url>
    </repository>
  </repositories>

Lokale Libraries einbinden

Die lokalen Libraries lassen sich wie gewohnt einbinden:

  <dependencies>
    <dependency>
      <groupId>de.deringo</groupId>
      <artifactId>companyLib</artifactId>
      <version>latest</version>
    </dependency>
    [...]
</dependencies>
Categories
Java

Generate Test Data

I need some test data to be displayed in my PrimeFaces Template App.

A good library to generate fake data is: Java Faker.

Add Java Faker to dependencies in Maven:

		<dependency>
			<groupId>com.github.javafaker</groupId>
			<artifactId>javafaker</artifactId>
			<version>1.0.2</version>
		</dependency>

For Example I want to have a Person with following fields:

	private String firstName;
	private String lastName;
	private Date dayOfBirth;
	private String phoneNumber;
	private String streetName;
	private String streetAddressNumber;
	private String zipCode;
	private String city;
	private String state;

A Person can be generated with fake data from Java Faker like this:

String firstName = faker.name().firstName();
String lastName = faker.name().lastName();
Date dayOfBirth = faker.date().birthday();
String phoneNumber = faker.phoneNumber().phoneNumber();
String streetName = faker.address().streetName();
String streetAddressNumber = faker.address().streetAddressNumber();
String zipCode = faker.address().zipCode();
String city = faker.address().city();
String state = faker.address().state();

Person person = new Person(firstName, lastName, dayOfBirth, phoneNumber, streetName, streetAddressNumber, zipCode, city, state);

Categories
Java

Test driven Json Analysis

To analyse an unknown Json API I setup a small project with Smallrye Rest Client to access the Json structure. I added JUnit for a test driven approach and Hamcrest for Matchers (like assertThat or is).

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

	<modelVersion>4.0.0</modelVersion>
	<groupId>deringo</groupId>
	<artifactId>testproject</artifactId>
	<version>1.0-SNAPSHOT</version>
	<name>testproject</name>
	<description></description>

	<properties>
		<maven.compiler.source>8</maven.compiler.source>
		<maven.compiler.target>8</maven.compiler.target>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
	</properties>

	<dependencies>
		<!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api -->
		<dependency>
			<groupId>org.junit.jupiter</groupId>
			<artifactId>junit-jupiter-api</artifactId>
			<version>5.7.0</version>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest -->
		<dependency>
			<groupId>org.hamcrest</groupId>
			<artifactId>hamcrest</artifactId>
			<version>2.2</version>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/io.smallrye/smallrye-rest-client -->
		<dependency>
			<groupId>io.smallrye</groupId>
			<artifactId>smallrye-rest-client</artifactId>
			<version>1.2.2</version>
		</dependency>
	</dependencies>

</project>
package deringo.testproject;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.junit.jupiter.api.Test;

public class TestJson {

	@Test
	public void testClientBuilderWorking() {
		Client client = ClientBuilder.newClient();
		WebTarget target = client.target("https://www.intensivregister.de/api/public/intensivregister");
		Response response = target.request(MediaType.APPLICATION_JSON).get();
		assertThat(response.getStatus(), is(200));
		JsonObject jo = response.readEntity(JsonObject.class);
		int rowCount = jo.getJsonNumber("rowCount").intValue();
		JsonArray ja = jo.getJsonArray("data");
		assertThat(ja.size(), is(rowCount));
		assertNotNull(ja.get(0).asJsonObject().getJsonObject("krankenhausStandort").getString("id"));

		ja.forEach(value -> 
				assertThat(
						value.asJsonObject().getString("id"),
						is(value.asJsonObject().getJsonObject("krankenhausStandort").getString("id"))
				));
	}

}
Categories
Java

Deploy to Tomcat with Maven

In my last post I decribed the way to build and deploy a war file to Tomcat application server with Ant.

In this post I show how to deploy the build war file to Tomcat application server with Maven.

Create inside the “ant” folder this Maven file:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>deringo</groupId>
    <artifactId>myApp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>myApp</name>
    <description>myApp Maven deployment</description>

    <properties>
        <java.version>1.8</java.version>
        <tomcat.version>8.5.33</tomcat.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-catalina</artifactId>
            <version>${tomcat.version}</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <warName>myApp</warName>
                    <wtpContextName>myApp</wtpContextName>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <url>http://myAppServer:7011/manager/text</url>
                    <username>tomcat</username>
                    <password>tomcat</password>
                    <warFile>dist/myApp.war</warFile>
                    <path>/myApp</path>
                    <update>true</update>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Execute with goal: tomcat7:deploy

Use Properties file

In my ANT file I have used a properties file for tomcat username/password etc. In my Maven script I want also to use this properties file.

Unfortunatly Maven can not handle property files out of the box. But there is a Plugin we can use:

        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>properties-maven-plugin</artifactId>
            <version>1.0-alpha-1</version>
            <executions>
                <execution>
                    <phase>initialize</phase>
                    <goals>
                        <goal>read-project-properties</goal>
                    </goals>
                    <configuration>
                        <files>
                            <file>tomcat.properties</file>
                        </files>
                    </configuration>
                </execution>
            </executions>
        </plugin>

This is the same, as writing this directly into pom.xml:

<properties>
    <tomcat.username>tomcat</tomcat.username>
    <tomcat.password>tomcat</tomcat.password>
</properties>

The complete pom.xml with properties:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>deringo</groupId>
  <artifactId>myApp</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>myApp</name>
  <description>myApp Maven deployment</description>

  <properties>
    <java.version>1.8</java.version>
    <tomcat.version>8.5.33</tomcat.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.apache.tomcat</groupId>
      <artifactId>tomcat-catalina</artifactId>
      <version>${tomcat.version}</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>properties-maven-plugin</artifactId>
        <version>1.0-alpha-1</version>
        <executions>
          <execution>
            <phase>initialize</phase>
            <goals>
              <goal>read-project-properties</goal>
            </goals>
            <configuration>
              <files>
                <file>tomcat.properties</file>
              </files>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <source>${java.version}</source>
          <target>${java.version}</target>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.2</version>
        <configuration>
          <failOnMissingWebXml>false</failOnMissingWebXml>
          <warName>myApp</warName>
          <wtpContextName>myApp</wtpContextName>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <url>${tomcat.manager.url}</url>
          <username>${tomcat.username}</username>
          <password>${tomcat.password}</password>
          <warFile>dist/myApp.war</warFile>
          <path>${webapp.name}</path>
          <update>true</update>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

Update 2021-03-24

I tried the configuration in a project but got this error:

Plugin execution not covered by lifecycle configuration: org.codehaus.mojo:properties-maven-plugin:1.0-alpha-1:read-project-properties (execution: default, phase: initialize)

I solved the error adding a pluginManagement tag:

<build>
    <pluginManagement>
        <plugins>
            <plugin> ... </plugin>
            <plugin> ... </plugin>
                  ....
        </plugins>
    </pluginManagement>
</build>

But this solution seems more like a workaround when reading the discussion on stackoverflow.
…need to search further…

Use in Jenkins

I have not tried it, but it should be possible to set an environment variable in Jenkins build step to execute with a configurable filename.

For example TOMCAT_PROPERTIES=jenkins-home/secret/tomcat-dev.properties.
And we can use it in Maven script this way:

            <configuration>
              <files>
                <file>${env.TOMCAT_PROPERTIES}</file>
              </files>
            </configuration>