English Documentation

Setup

Setting up the Faktor-IPS Product Designer with custom product projects

The following describes the process for manually setting up the Product Designer as a local Spring Boot application with custom product projects, as well as subsequent deployment via Docker.

Updating Faktor-IPS Dependencies:

The Product Designer requires the latest Faktor-IPS version (currently 24.7) and Java 21. In the first step, the Faktor-IPS dependencies must be updated, and the current Faktor-IPS version must be installed in a suitable Eclipse via the update site. Subsequently, the model projects need to be rebuilt once. For more information on compatibilities between Faktor-IPS and Eclipse, please refer to this overview.

Creating a Maven project:

Next, a new Maven project is created with dependencies for the Product Designer, model projects, and Spring Boot starter.

Please note: In addition to the manual setup described below, there is also the option to generate a Maven Product Designer project using an archetype. More information on this can be found in the chapter 'Product Designer Archetype'.

Dependencies:

Productdesigner-Web:

  <dependencies>
        <dependency>
            <groupId>org.faktorips.productdesigner</groupId>
            <artifactId>productdesigner-web</artifactId>
            <version>24.7.0</version>
        </dependency>
  </dependencies>

Add required model dependencies – for example:

 <dependencies>
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-gruppenunfall-produktmodellerw</artifactId>
            <version>24.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-basis-produkte</artifactId>
            <version>24.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
 </dependencies>

In the Spring Boot plugin configuration, the Product Designer application created in the following step is registered:

            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <wait>500</wait>
                    <maxAttempts>240</maxAttempts>
                    <!-- Insert the Product Designer Application here (see below) -->
                    <mainClass>org.faktorips.productdesigner.demo.SampleProductDesignerApplication</mainClass>
                    <layout>JAR</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

Below is an example pom.xml of a Product Designer Maven project:

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>de.faktorzehn.commons</groupId>
        <artifactId>f10-suite-starter-spring</artifactId>
        <version>24.7.0</version>
    </parent>
    <groupId>org.faktorips.productdesigner</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <java.version>21</java.version>
        <maven.compiler.release>${java.version}</maven.compiler.release>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
        <faktorips.version>24.7.0</faktorips.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.faktorips.productdesigner</groupId>
            <artifactId>productdesigner-web</artifactId>
            <version>24.7.0</version>
        </dependency>
        <!-- INSERT the model dependencies here -->
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-gruppenunfall-produktmodellerw</artifactId>
            <version>24.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>de.faktorzehn.muster.shu-gewerbe</groupId>
            <artifactId>vm-gewerbe-basis-produkte</artifactId>
            <version>24.7.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>spring-boot:run</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <wait>500</wait>
                    <maxAttempts>240</maxAttempts>
                    <!-- Insert the Product Designer Application here -->
                    <mainClass>org.faktorips.productdesigner.demo.SampleProductDesignerApplication</mainClass>
                    <layout>JAR</layout>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-frontend</goal>
                        </goals>
                        <phase>compile</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Creating a Spring Boot Application Class

Next, create an application class, which will be registered in the pom.xml under the configuration of the spring-boot-maven-plugin. Example: SampleProductDesignerApplication.java:

import com.vaadin.flow.component.page.AppShellConfigurator;
import com.vaadin.flow.server.AppShellSettings;
import com.vaadin.flow.spring.annotation.EnableVaadin
import com.vaadin.flow.theme.Theme;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.faktorips.productdesigner.core.ProductDesigner;
import org.faktorips.productdesigner.core.ProductDesignerConfigurationProperties;

@Theme(value = "productdesigner", variant = "card-section-pages")
@SpringBootApplication(scanBasePackages = ProductDesigner.BASE_PACKAGE)
@EnableConfigurationProperties(ProductDesignerConfigurationProperties.class)
@EnableVaadin(value = ProductDesigner.BASE_PACKAGE)
public class SampleProductDesignerApplication implements AppShellConfigurator {

    private static final long serialVersionUID = 1L;

    public static void main(String[] args) {
        SpringApplication.run(SampleProductDesignerApplication.class, args);
    }

    @Override
    public void configurePage(AppShellSettings settings) {
        settings.addFavIcon("icon", "../favicon.ico", "48x48");
    }
}

Creating the Configuration and Including Additional Repositories

Now, under src/main/resources/, create an application.yml:

logging:
  level:
    org.springframework: WARN

server:
  port: 8080

vaadin:
  urlMapping: '/ui/*'
  launch-browser: true

ips-product-designer:
  ips-project-path: ../../../git/mustercontent/vm/vm.shu.gewerbe/gruppenunfall/produkte/
  additional-repos:
    - de.faktorzehn.versicherungsmodell.gw.produkte.GwProduktClassloaderRuntimeRepository
    - de.faktorzehn.versicherungsmodell.gw.produkte.GwAllgemeinClassloaderRuntimeRepository
  read-only-mode: false

In the additional-repos section, repositories on which the product project depends are included by their class references.

To ensure they are correctly loaded at runtime, each repository should have a class with an INSTANCE field for an IRuntimeRepository or IRuntimeRepositoryLookup.

For example, the class GwProduktClassloaderRuntimeRepository referenced in the .yml for providing and configuring the singleton repository looks like this:

import org.faktorips.runtime.ClassloaderRuntimeRepository;
import org.faktorips.runtime.formula.groovy.GroovyFormulaEvaluatorFactory;

public class GwProduktClassloaderRuntimeRepository {

    public static final ClassloaderRuntimeRepository INSTANCE = ClassloaderRuntimeRepository
            .create("de/faktorzehn/versicherungsmodell/gw/produkte/internal/faktorips-repository-toc.xml");

    static {
        INSTANCE.addDirectlyReferencedRepository(GwAllgemeinClassloaderRuntimeRepository.INSTANCE);
        INSTANCE.setFormulaEvaluatorFactory(new GroovyFormulaEvaluatorFactory());
    }

    private GwProduktClassloaderRuntimeRepository() {
        // Soll nicht instanziiert werden
    }

}

First, a ClassloaderRuntimeRepository INSTANCE is initialized based on the associated toc.xml. In the static initialization block, necessary referenced repositories are then incorporated via their respective instances (INSTANCE.addDirectlyReferencedRepository(GwAllgemeinClassloaderRuntimeRepository.INSTANCE)), and additionally, configurations for the repository instance are defined (INSTANCE.setFormulaEvaluatorFactory(new GroovyFormulaEvaluatorFactory());).

Adding a Favicon

Finally, to display application icons in the browser tab, a favicon can optionally be placed in src/main/resources/static.

Docker Deployment

When providing and deploying the application in Docker containers, it should be noted that the application is deployed as a .jar file, but the product data is unpacked and copied into the container. For this, the vaadin.productionMode must first be set to true in the pom.xml.

<profiles>
    <profile>
        <id>production</id>
        <properties>
            <vaadin.productionMode>true</vaadin.productionMode>
        </properties>
        <build>
            <plugins>
                <plugin>
                    <groupId>com.vaadin</groupId>
                    <artifactId>vaadin-maven-plugin</artifactId>
                    <version>${vaadin.version}</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>prepare-frontend</goal>
                                <goal>build-frontend</goal>
                            </goals>
                            <phase>compile</phase>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Dockerfile example:

FROM eclipse-temurin:21-jre-jammy
RUN apt-get update \
    && ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime \
    && dpkg-reconfigure -f noninteractive tzdata
ARG UID=999
ARG GID=999
ENV JAVA_TOOL_OPTIONS "-Xms480m -Xmx1024m"
RUN groupadd --gid $GID spring \
    && useradd -r -m -d /opt/spring -s /sbin/nologin --gid $GID --uid $UID -c "Spring user" spring \
    && chmod 755 /opt/spring \
    && mkdir -p /var/opt/spring \
    && chown spring: /var/opt/spring \
    && chmod 755 /var/opt/spring
WORKDIR /opt/spring
COPY ${PATH_TO_APPLICATION_JAR} application.jar
COPY ${PATH_TO_PRODUCT_FOLDER} /var/opt/spring/produkte
RUN chown -R spring: /var/opt/spring
USER $UID
EXPOSE 8080
CMD ["java", \
    "-Dspring.profiles.active=production", \
    "-jar", \
    "application.jar", \
    "--server.port=8080", \
    "--server.forward-headers-strategy=FRAMEWORK"]

docker-compose.yml example:

version: '2.4'

services:
  productdesigner-sample:
    container_name: ${CONTAINER_NAME}-sample
    build:
      context: ../
      dockerfile: ./path/to/Dockerfile
      args:
      - PATH_TO_APPLICATION_JAR=${PATH_TO_APPLICATION_JAR}
      - PATH_TO_PRODUCT_FOLDER=${PATH_TO_PRODUCT_FOLDER}
    environment:
      SPRING_PROFILES_ACTIVE: production
      ips-product-designer.ips-project-path: /var/opt/spring/produkte
    labels:
      url: ${CONTAINER_NAME}-sample
      entry-path: ui

networks:
    default:
        name: network-${CONTAINER_NAME}
        labels:
            retention: ${CONTAINER_RETENTION}