Skip to content

ExplorViz/persistence-service

Repository files navigation

persistence-service

The persistence-service acts as a database service and stores the runtime and evolution data generated by the span-service and the code-agent. This data is made available to the frontend.

All data is persisted in a graph database using Neo4j. The database model is shown below.

For the REST API as well as communication via gRPC and Kafka, we use the Quarkus framework. All interactions with the Neo4j database are performed through the Neo4j-OGM library by using the corresponding Quarkus integration.

The persistence-service communicates with the code-agent via gRPC and with the span-service via Apache Kafka. It provides a REST-API for the frontend.

Table of Contents

Development Instructions

Prerequisites

  • Java: JDK 17 or higher
  • Docker: Installed and running, since the persistence-service starts its own Docker container in dev mode and when running tests

Code Style

Formatting

We recommend using the IntelliJ IDEA IDE. Your code should follow the Google Java Style Guide. This is enforced using Spotless as part of a pre-commit hook. Before committing, run ./gradlew spotlessApply to automatically fix any formatting issues.

To integrate this format with IntelliJ's formatter (Ctrl + Alt + L shortcut), we recommend the official google-java-format plugin. Carefully follow these instructions to install it. Alternatively, you can use one of the plugins for the Spotless IDE hook. This hook also integrates with Visual Studio Code.

Pre-commit hook

As part of a git pre-commit hook, your code is checked using Spotless, Checkstyle and PMD. If any of these checks fails, the commit is blocked until the issues are resolved. Additionally, all tests must pass for the commit to be successful. Please ensure that all issues are adequately resolved before commiting your changes. If absolutely required, you can skip the pre-commit hook validation using the --no-verify flag, but ensure the issues are addressed before creating a merge request.

Running the application in dev mode

You can run your application in dev mode that enables live reloading using:

./gradlew quarkusDev

When starting the persistence-service in dev mode, a Neo4j Docker container is automatically started as part of Quarkus's Dev Services. If an existing Neo4j container is reachable via the default URI (http://localhost:7687), e.g. when running Neo4j as part of the Docker deployment or via the Docker compose included in this repository's .dev folder, then that instance is used instead.

An overview of the available endpoints is provided in the Quarkus Dev UI at http://localhost:8085/q/dev/. If you are only concerned with providing data to the frontend, you can use the dev-exclusive /example endpoints to populate the database with example data.

You can also inspect and manipulate the current state of the database using Neo4j Browser. By default, the browser runs on http://localhost:7474.

Packaging and running the application

The application can be packaged using:

./gradlew build

It produces the quarkus-run.jar file in the build/quarkus-app/ directory. Be aware that it’s not an über-jar as the dependencies are copied into the build/quarkus-app/lib/ directory.

The application is now runnable using java -jar build/quarkus-app/quarkus-run.jar.

If you want to build an über-jar, execute the following command:

./gradlew build -Dquarkus.package.jar.type=uber-jar

The application, packaged as an über-jar, is now runnable using java -jar build/*-runner.jar.

Creating a native executable

You can create a native executable using:

./gradlew build -Dquarkus.native.enabled=true

Or, if you don't have GraalVM installed, you can run the native executable build in a container using:

./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true

You can then execute your native executable with: ./build/persistence-service-1.0.0-SNAPSHOT-runner

If you want to learn more about building native executables, please consult https://quarkus.io/guides/gradle-tooling.

Testing

To ensure the persistence-service is working properly, there are a number of tests that can be executed using the following command:

./gradlew quarkusTest

The tests are also run as part of the git pre-commit hook.

Database Model

Model of database

Node Fields

Application

Field Type
id Long
name String

Branch

Field Type
id Long
name String

Clazz

Field Type
id Long
name String
type ClassType
modifiers Set<String>
implementedInterfaces Set<String>
annotations Set<String>
enumValues Set<String>
metrics Map<String, Double>

Commit

Field Type
id Long
hash String
author String
authorDate Instant
commitDate Instant

Directory

Field Type
id Long
name String

Field

Field Type
id Long
name String
type String
modifiers List<String>

FileRevision

Field Type
id Long
name String
hash String
hasFileData boolean
language Language
packageName String
importNames Set<String>
lastEditor String
addedLines int
modifiedLines int
deletedLines int
metrics Map<String, Double>

Function

Field Type
id Long
name String
returnType String
constructor boolean
annotations Set<String>
modifiers Set<String>
outgoingMethodCalls Set<String>
startLine int
endLine int
metrics Map<String, Double>

Landscape

Field Type
tokenId String

Parameter

Field Type
id Long
name String
type String
modifiers List<String>

Repository

Field Type
id Long
name String

Span

Field Type
id Long
spanId String
startTime long
endTime long

Tag

Field Type
id Long
name String

Trace

Field Type
id Long
traceId String
startTime Long
endTime Long

Updating the Database Model

The database model was created using the web application arrows.app. It is free to use and is officially recommended by Neo4j.

The model can be exported in formats such as PNG and JSON. The latest versions can be found under ./resources/. You can import the model via JSON or create a resource link that loads the entire model.

Link to the model

Please note: After every change to the model, the JSON file at ./resources/db_model.json must be updated, and the PNG file at ./resources/db_model.png should also be replaced with a new PNG export. In addition, the link in this README.md file must be updated to the new link.

REST-API

The persistence-service provides a REST-API for the frontend. There are two versions available.

v2

Version 2 offers the standard endpoints that were used prior to the switch to the persistence-service. This can be used to work with older versions of the frontend. For developing new features, please refer to the version 3 of the API.

GET /v2/landscapes/{landscapeToken}/structure

LandscapeDto getStructureData(String landscapeToken);

Returns the landscape associated with a landscape token.

GET /v2/landscapes/{landscapeToken}/dynamic?from={}&to={}

List<TraceDto> getDynamicData(String landscapeToken, Long from, Long to);

Returns all traces associated with a landscape. Optionally, a time range can be specified.

GET /v2/landscapes/{landscapeToken}/timestamps?oldest={}&newest={}&commit={}

Multi<TimestampDto> getTimestamps(
        String landscapeToken, Long newest, Long oldest, String commit);

Returns timestamps associated with a landscape. Optionally, a time range and a commit can be specified.

GET /v2/code/applications/{landscapeToken}

List<String> getStaticApplicationNamesForLandscape(String landscapeToken);

Returns the names of all applications in a landscape that are backed by data from git evolution analysis.

GET /v2/code/commit-tree/{landscapeToken}/{applicationName}

CommitTreeDto getCommitTreeForApplicationAndLandscape(String landscapeToken, String applicationName);

Returns the tree of commits associated with a landscape and an application.

GET /v2/code/metrics/{landscapeToken}/{applicationName}/{commitHash}

ApplicationMetricsCodeDto getStaticCodeMetricsForApplicationAndCommit(
        String landscapeToken, String applicationName, String commitHash);

Returns the code metrics associated with a landscape, an application, and a commit.

GET /v2/code/structure/{landscapeToken}/{applicationName}/{commitHash}

LandscapeDto getStaticStructureForApplicationAndSingleCommit(
        String landscapeToken, String applicationName, String commitHash);

Returns the landscape structure associated with a landscape, an application, and a commit.

GET /v2/code/structure/{landscapeToken}/{applicationName}/{firstCommitHash}-{secondCommitHash}

LandscapeDto getStaticStructureForApplicationAndTwoCommits(
        String landscapeToken, String applicationName, String firstCommitHash, String secondCommitHash);

Returns the union of the landscape structures associated with two commits of an application in a landscape.

GET /v2/code/commit-comparison/{landscapeToken}/{applicationName}/{firstCommitHash}-{secondCommitHash}

CommitComparison getCommitComparison(
        String landscapeToken, String applicationName, String firstCommitHash, String secondCommitHash);

Returns a comparison object of two commits associated with a landscape and an application.

DELETE /v2/code/landscapes/{landscapeToken}/trace-data

void deleteTraceData(String landscapeToken);

Deletes all data gathered from runtime analysis associated with a landscape from the database.

v3

Version 3 features a redesign of the endpoints, allowing many of the calculations to be moved from the frontend to the persistence-service. The central change is the switch to a flat data model as opposed to a deeply nested one, allowing fast lookups for visualization objects.

Be sure to update this README when implementing new endpoints.

GET /v3/landscapes/{landscapeToken}/structure/runtime

FlatLandscapeDto getRuntimeStructureData(String landscapeToken);

Returns all landscape structure data gathered from runtime analysis for a landscape.

GET /v3/landscapes/{landscapeToken}/structure/evolution/{repositoryName}/{commitHash}

FlatLandscapeDto getStaticStructureData(String landscapeToken, String repositoryName, String commitHash);

Retrieve landscape structure data gathered from static analysis for a particular repository and commit in a landscape.

GET /v3/landscapes/{landscapeToken}/structure/evolution/{repositoryName}/{firstCommitHash}-{secondCommitHash}

FlatLandscapeDto getCombinedStaticStructureData(String landscapeToken, String repositoryName, String firstCommitHash, String secondCommitHash);

Retrieve the union of landscape structure data for the two provided commits within the given landscape and repository. The value for the commitComparison attribute is set relative to the second commit, e.g. "DELETED" is written if some component is present in the first commit, but not the second.

GET /v3/landscapes/{landscapeToken}/dynamic?from={}&to={}

List<TraceDto> getDynamicData(String landscapeToken, Long from, Long to);

Returns all traces associated with a landscape. Optionally, a time range can be specified.

GET /v3/landscapes/{landscapeToken}/timestamps?oldest={}&newest={}&commit={}

List<TimestampDto> getTimestamps(String landscapeToken, Long newest, Long oldest, String commit);

Returns timestamps associated with a landscape. Optionally, a time range and a commit can be specified.

GET /v3/landscapes/{landscapeToken}/repositories

List<String> getRepositoryNames(String landscapeToken);

Retrieves the names of all repositories in a landscape.

GET /v3/landscapes/{landscapeToken}/commit-tree/{repositoryName}

CommitTreeDto getCommitTreeForRepositoryAndLandscape(String landscapeToken, String repositoryName);

Returns the tree of commits associated with a repository in a landscape.

DELETE /v3/landscapes/{landscapeToken}/trace-data

void deleteTraceData(String landscapeToken);

Deletes all data gathered from runtime analysis associated with a landscape from the database.

About

Service that manages a Neo4j graph database.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors