diff --git a/.java-version b/.java-version
index 98d9bcb75..5f39e9144 100644
--- a/.java-version
+++ b/.java-version
@@ -1 +1 @@
-17
+21.0
diff --git a/felles/abac/pom.xml b/felles/abac/pom.xml
index baca8823e..98c5a8a46 100644
--- a/felles/abac/pom.xml
+++ b/felles/abac/pom.xml
@@ -19,8 +19,8 @@
felles-feil
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
no.nav.foreldrepenger.felles
diff --git a/felles/konfig/README.md b/felles/konfig/README.md
new file mode 100644
index 000000000..3fddd6888
--- /dev/null
+++ b/felles/konfig/README.md
@@ -0,0 +1,91 @@
+### OBS!!! Deprecated - funksjonalitet ble flyttet til fp-felles og utvikler videre der.
+
+[![Bygg](https://github.com/navikt/fp-konfig/actions/workflows/build.yml/badge.svg)](https://github.com/navikt/fp-konfig/actions/workflows/build.yml)
+
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=navikt_fp-konfig&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=navikt_fp-konfig)
+[![Lines of Code](https://sonarcloud.io/api/project_badges/measure?project=navikt_fp-konfig&metric=ncloc)](https://sonarcloud.io/summary/new_code?id=navikt_fp-konfig)
+[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=navikt_fp-konfig&metric=coverage)](https://sonarcloud.io/summary/new_code?id=navikt_fp-konfig)
+[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=navikt_fp-konfig&metric=bugs)](https://sonarcloud.io/summary/new_code?id=navikt_fp-konfig)
+[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=navikt_fp-konfig&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=navikt_fp-konfig)
+[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=navikt_fp-konfig&metric=security_rating)](https://sonarcloud.io/summary/new_code?id=navikt_fp-konfig)
+
+![GitHub release (latest by date)](https://img.shields.io/github/v/release/navikt/fp-konfig)
+![GitHub](https://img.shields.io/github/license/navikt/fp-konfig)
+
+
+# fp-konfig
+
+Java/CDI basert bibliotek som brukes til å håndtere app konfigurasjon avhengig av kubernetes cluster og namespace applikasjonen kjører i.
+
+Det er mulig å injecte en spesifikk variable i en konstruktor eller felt ved å bruke ``@KonfigVerdi`` annotering.
+
+## Bruk
+
+### Konfig kilder
+
+Biblioteket leter etter konfig i følgende kilder og bruker første verdi fra kilden hvor den finnes.
+
+Prioriteten på kilder er som følge:
+
+- Applikasjons properties med cluster og namespace (*application-prod-fss-default.properties*)
+- Applikasjons properties med cluster (*application-prod-fss.properties*)
+- Applikasjons properties (*application.properties*)
+- Miljø variabler (generelt alt som finnes i *System.getenv()*)
+- System properties (generelt alt som finnes i *System.getProperties()*)
+
+For kjøring utenfor kubernetes f.eks. fra IDE defaultes cluster navn til "local" og namespace til verdi satt
+i System.getProperty("app.name");
+Dvs at man kan nå properties under application.properties, application-lokal.properties og application-lokal-.properties
+
+Det er mulig å plugge inn en egen provider ved å implementere `PropertiesKonfigVerdiProvider` klassen.
+
+Løsningen er CDI basert.
+
+### Bruk av `@KonfigVerdi`
+
+Det er mulig å direkte `@Injecte` konfig som trenger ved å bruke `@KonfigVerdi` annotering i konstruktor eller direkte på et attribut.
+Minimum oppsett:
+
+- ```@KonfigVerdi(value = "min.property") String minProperty```
+- ```@KonfigVerdi(value = "min.property", required=false) String minProperty``` - kaster ikke exception om verdien ikke finnes.
+- ```@KonfigVerdi(value = "min.property", defaultVeidi="default konfig verdi") String minProperty``` - returnerer default verdi om verdien ikke finnes i konfig.
+- ```
+ @KonfigVerdi(value = "min.property")
+ private String minProperty
+
+Det er mulig å hente konfig direkte fra koden ved å kalle `getProperty` eller `getRequiredProperty` fra `Environment` klassen:
+
+- ```Environment.current().getProperty("min.property")``` - returnerer en String eller null om det ikke finnes.
+- ```Environment.current().getProperty("min.property", Integer.class)``` - returnerer en Integer, null om det ikke finnes eller Exception om ikke integer.
+- ```Environment.current().getRequiredProperty("min.property")``` - returnerer en String, eller Exception om verdien ikke finnes.
+
+Følgende typer støttes og kan bli returnert:
+
+- String (default)
+- Boolean / boolean
+- Integer / int
+- Period
+- Duration
+- LocalDate
+- Long
+- URI
+- URL
+
+### Bruk eksempler
+
+- ```@KonfigVerdi(value = "test.enabled", required = false) boolean enabled``` == ```Environment.current().getProperty("test.enabled", integer.class)```
+- ```@KonfigVerdi(value = "bruker.navn" String bruker``` == ```Environment.current().getProperty("bruker.navn")```
+- ```@KonfigVerdi(value = "periode.fp") Period periode``` == ```Environment.current().getProperty("periode.fp", Period.class)```
+- ```@KonfigVerdi(value = HENDELSE_BASE_ENDPOINT, defaultValue=DEFAULT_BASE_ENDPOINT) URI baseEndpoint``` == ```Environment.current().getProperty(HENDELSE_BASE_ENDPOINT, URI.class, DEFAULT_BASE_ENDPOINT)```
+
+### Utilities
+
+- `Environment` - statisk klasse som gir informasjon om miljøet appen kjører i.
+- `Cluster` - statisk klasse med info om clusteret appen kjører i f.eks: isProd(), isDev(), isLocal(), etc.
+- `Namespace` - statisk klasse som leverer egenskaper om namespacet appen kjører i f.eks: getName()
+- `Application` - statisk klasse som leverer injisert navn på applikasjon: getName()
+- `ClienId` - statisk klasse som leverer egenskaper om clientId for appen: getClientId()
+
+### Lisens
+
+MIT
diff --git a/felles/konfig/pom.xml b/felles/konfig/pom.xml
new file mode 100644
index 000000000..912847ec9
--- /dev/null
+++ b/felles/konfig/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+
+ felles
+ no.nav.foreldrepenger.felles
+ 0.0.0-SNAPSHOT
+
+
+ felles-konfig
+
+
+
+ jakarta.enterprise
+ jakarta.enterprise.cdi-api
+ provided
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ true
+
+ prod-fss
+ default
+
+
+
+
+
+
+
+
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Application.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Application.java
new file mode 100644
index 000000000..962cb6be5
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Application.java
@@ -0,0 +1,32 @@
+package no.nav.foreldrepenger.konfig;
+
+import static java.lang.System.getenv;
+
+import java.util.Optional;
+
+public class Application {
+
+ private final String name;
+
+ private Application(String name) {
+ this.name = name;
+ }
+
+ public static Application of(String name) {
+ return new Application(name);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public static Application current() {
+ return Application.of(Optional.ofNullable(getenv(NaisProperty.APPLICATION.propertyName())).orElse("vtp"));
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[application=" + name + "]";
+ }
+
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/ApplicationPropertiesKonfigProvider.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/ApplicationPropertiesKonfigProvider.java
new file mode 100644
index 000000000..ce3826305
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/ApplicationPropertiesKonfigProvider.java
@@ -0,0 +1,104 @@
+package no.nav.foreldrepenger.konfig;
+
+import static java.lang.System.getenv;
+import static no.nav.foreldrepenger.konfig.StandardPropertySource.APP_PROPERTIES;
+
+import java.io.IOException;
+import java.util.Optional;
+import java.util.Properties;
+
+import jakarta.enterprise.context.Dependent;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import no.nav.foreldrepenger.konfig.KonfigVerdi.Converter;
+
+@Dependent
+public class ApplicationPropertiesKonfigProvider extends PropertiesKonfigVerdiProvider {
+
+ static class Init {
+ // lazy init singleton
+ static final Properties PROPS = lesFra();
+ private static final String SUFFIX = ".properties";
+ private static final String PREFIX = "application";
+
+ private Init() {
+ }
+
+ private static Properties lesFra() {
+ var c = new Properties();
+ lesFra(namespaceKonfig(), lesFra(clusterKonfig(), lesFra("", new Properties())))
+ .forEach((k, v) -> c.put(k.toString().toLowerCase(), v.toString()));
+ return c;
+ }
+
+ private static Properties lesFra(String infix, Properties p) {
+ if (infix == null) {
+ return p;
+ }
+ String navn = PREFIX + infix + SUFFIX;
+ try (var is = ApplicationPropertiesKonfigProvider.class.getClassLoader().getResourceAsStream(navn)) {
+ if (is != null) {
+ LOG.info("Laster properties fra {}", navn);
+ p.load(is);
+ return p;
+ }
+ } catch (IOException e) {
+ LOG.info("Propertyfil {} ikke lesbar", navn);
+ }
+ LOG.info("Propertyfil {} ikke funnet", navn);
+ return p;
+ }
+
+ private static String namespaceKonfig() {
+ var namespaceName = namespaceName();
+ if (namespaceName != null) {
+ return clusterKonfig() + "-" + namespaceName;
+ } else {
+ var appName = System.getProperty("app.name");
+ if (appName != null) {
+ return clusterKonfig() + "-" + appName;
+ }
+ }
+ return null;
+ }
+
+ private static String namespaceName() {
+ return getenv(NaisProperty.NAMESPACE.propertyName());
+ }
+
+ private static String clusterKonfig() {
+ return "-" + clusterName();
+ }
+
+ private static String clusterName() {
+ return Optional.ofNullable(getenv(NaisProperty.CLUSTER.propertyName()))
+ .orElse(Cluster.VTP.clusterName());
+ }
+ }
+
+ private static final int PRIORITET = EnvPropertiesKonfigVerdiProvider.PRIORITET + 1;
+
+ private static final Logger LOG = LoggerFactory.getLogger(ApplicationPropertiesKonfigProvider.class);
+
+ public ApplicationPropertiesKonfigProvider() {
+ super(Init.PROPS, APP_PROPERTIES);
+ }
+
+ @Override
+ public V getVerdi(String key, Converter converter) {
+ return Optional.ofNullable(super.getVerdi(key.toLowerCase(), converter))
+ .orElse(null);
+ }
+
+ @Override
+ public boolean harVerdi(String key) {
+ return super.harVerdi(key.toLowerCase());
+ }
+
+ @Override
+ public int getPrioritet() {
+ return PRIORITET;
+ }
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/ClientId.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/ClientId.java
new file mode 100644
index 000000000..ab1a1162e
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/ClientId.java
@@ -0,0 +1,44 @@
+package no.nav.foreldrepenger.konfig;
+
+import static java.lang.System.getenv;
+
+public class ClientId {
+
+ private static final String DELIMIT = ":";
+
+ private final String id;
+
+ private ClientId(String clientId) {
+ this.id = clientId;
+ }
+
+ public static ClientId of(String clientId) {
+ return new ClientId(clientId);
+ }
+
+ public static ClientId of(Cluster cluster, Namespace namespace, Application application) {
+ return of(cluster.clusterName(), namespace.getName(), application.getName());
+ }
+
+ public static ClientId of(Cluster cluster, Namespace namespace, String application) {
+ return of(cluster.clusterName(), namespace.getName(), application);
+ }
+
+ private static ClientId of(String cluster, String namespace, String application) {
+ return of(cluster + DELIMIT + namespace + DELIMIT + application);
+ }
+
+ public String getClientId() {
+ return id;
+ }
+
+ public static ClientId current() {
+ return ClientId.of(getenv(NaisProperty.CLIENTID.propertyName()));
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[clientId=" + id + "]";
+ }
+
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Cluster.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Cluster.java
new file mode 100644
index 000000000..b883d1e65
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Cluster.java
@@ -0,0 +1,78 @@
+package no.nav.foreldrepenger.konfig;
+
+import static java.lang.System.getenv;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+public enum Cluster {
+ VTP("vtp"),
+ DEV_FSS("dev-fss"),
+ DEV_GCP("dev-gcp"),
+ PROD_GCP("prod-gcp"),
+ PROD_FSS("prod-fss");
+
+ private static final String PROD = "prod";
+ private static final String DEV = "dev";
+ private static final String FSS = "fss";
+ private static final String GCP = "gcp";
+
+ private final String name;
+
+ Cluster(String name) {
+ this.name = name;
+ }
+
+ public String clusterName() {
+ return name;
+ }
+
+ public boolean isProd() {
+ return name.startsWith(PROD);
+ }
+
+ public boolean isDev() {
+ return name.startsWith(DEV);
+ }
+
+ boolean isVTP() {
+ return name.startsWith(VTP.name);
+ }
+
+ boolean isFss() {
+ return name.endsWith(FSS);
+ }
+
+ boolean isGcp() {
+ return name.endsWith(GCP);
+ }
+
+ public boolean isLocal() {
+ return !isProd() && !isDev();
+ }
+
+ public boolean isSameClass(Cluster other) {
+ return name.substring(0, 2).equals(other.name.substring(0, 2));
+ }
+
+ public boolean isCoLocated(Cluster other) {
+ return name.substring(name.length() - 3).equals(other.name.substring(other.name.length() - 3));
+ }
+
+ public static Cluster current() {
+ var active = getenv(NaisProperty.CLUSTER.propertyName());
+ return Arrays.stream(values())
+ .filter(c -> active != null && Objects.equals(active, c.name))
+ .findFirst()
+ .orElse(VTP);
+ }
+
+ public static Cluster of(String name) {
+ return Arrays.stream(values())
+ .filter(v -> v.name.equals(name))
+ .findFirst()
+ .orElseThrow();
+ }
+
+
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/DefaultValueKonfigProvider.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/DefaultValueKonfigProvider.java
new file mode 100644
index 000000000..55b5dd5d6
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/DefaultValueKonfigProvider.java
@@ -0,0 +1,57 @@
+package no.nav.foreldrepenger.konfig;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.stream.Collectors;
+
+import no.nav.foreldrepenger.konfig.KonfigVerdi.Converter;
+
+public class DefaultValueKonfigProvider implements KonfigVerdiProvider {
+
+ @Override
+ public PropertySourceMetaData getAllProperties() {
+ return new PropertySourceMetaData(StandardPropertySource.DEFAULT, new Properties());
+ }
+
+ @Override
+ public StandardPropertySource getSource() {
+ return StandardPropertySource.DEFAULT;
+ }
+
+ @Override
+ public V getVerdi(String verdi, Converter converter) {
+ return converter.tilVerdi(verdi);
+ }
+
+ @Override
+ public List getVerdier(String verdier, Converter converter) {
+ return Arrays.stream(verdier.split(",\\s*"))
+ .map(converter::tilVerdi)
+ .toList();
+
+ }
+
+ @Override
+ public Map getVerdierAsMap(String verdier, Converter converter) {
+ return Arrays.stream(verdier.split(",\\s*"))
+ .map(s -> s.split(":\\s*"))
+ .collect(
+ Collectors.toMap(
+ e -> e[0],
+ e -> converter.tilVerdi(e[1])
+ ));
+ }
+
+ @Override
+ public boolean harVerdi(String key) {
+ return true;
+ }
+
+ @Override
+ public int getPrioritet() {
+ return 0;
+ }
+
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/EnvPropertiesKonfigVerdiProvider.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/EnvPropertiesKonfigVerdiProvider.java
new file mode 100644
index 000000000..0b4930f5f
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/EnvPropertiesKonfigVerdiProvider.java
@@ -0,0 +1,53 @@
+package no.nav.foreldrepenger.konfig;
+
+import no.nav.foreldrepenger.konfig.KonfigVerdi.Converter;
+
+import jakarta.enterprise.context.Dependent;
+import java.util.Optional;
+import java.util.Properties;
+
+import static no.nav.foreldrepenger.konfig.StandardPropertySource.ENV_PROPERTIES;
+
+@Dependent
+public class EnvPropertiesKonfigVerdiProvider extends PropertiesKonfigVerdiProvider {
+
+ public static final int PRIORITET = SystemPropertiesKonfigVerdiProvider.PRIORITET + 1;
+
+ static class Init {
+ // lazy init singleton
+ static final Properties ENV = getEnv();
+
+ private Init() {
+ }
+
+ private static Properties getEnv() {
+ var p = new Properties();
+ p.putAll(System.getenv());
+ return p;
+ }
+ }
+
+ public EnvPropertiesKonfigVerdiProvider() {
+ super(Init.ENV, ENV_PROPERTIES);
+ }
+
+ @Override
+ public V getVerdi(String key, Converter converter) {
+ return Optional.ofNullable(super.getVerdi(key, converter))
+ .orElse(super.getVerdi(upper(key), converter));
+ }
+
+ @Override
+ public boolean harVerdi(String key) {
+ return super.harVerdi(key) || super.harVerdi(upper(key));
+ }
+
+ private static String upper(String key) {
+ return key.toUpperCase().replace('.', '_');
+ }
+
+ @Override
+ public int getPrioritet() {
+ return PRIORITET;
+ }
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Environment.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Environment.java
new file mode 100644
index 000000000..ee7f022c8
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/Environment.java
@@ -0,0 +1,264 @@
+package no.nav.foreldrepenger.konfig;
+
+import static java.lang.System.getenv;
+
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.net.URL;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.Period;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.function.Supplier;
+import java.util.stream.Collectors;
+
+import no.nav.foreldrepenger.konfig.KonfigVerdi.*;
+
+public final class Environment {
+
+ static final class Init {
+ // Josh Bloch's lazy load singleton (ref "Effective Java").
+ // Siden Init ikke lastes før den referes blir feltet her initiert først når den aksesseres første gang.
+ static final Environment CURRENT = of(Cluster.current(), Namespace.current(), Application.current(),
+ ClientId.current(), currentImage());
+
+ private Init() {
+ }
+
+ private static Environment of(Cluster cluster, Namespace namespace, Application application,
+ ClientId clientId, String image) {
+ var ensureClientId = Optional.ofNullable(clientId).orElseGet(() -> composeClientId(cluster, namespace, application));
+ return new Environment(cluster, namespace, application, ensureClientId, image);
+ }
+
+ private static ClientId composeClientId(Cluster cluster, Namespace namespace, Application application) {
+ return ClientId.of(cluster.clusterName() + ":" + namespace.getName() + ":" + application.getName());
+ }
+
+ private static String currentImage() {
+ return getenv(NaisProperty.IMAGE.propertyName());
+ }
+
+ }
+
+ private final Cluster cluster;
+ private final Namespace namespace;
+ private final Application application;
+ private final ClientId clientId;
+ private final String imageName;
+ private final List propertySources;
+
+ private Environment(Cluster cluster, Namespace namespace, Application application, ClientId clientId, String imageName) {
+ this.cluster = cluster;
+ this.namespace = namespace;
+ this.application = application;
+ this.clientId = clientId;
+ this.imageName = imageName;
+ this.propertySources = List.of(
+ new SystemPropertiesKonfigVerdiProvider(),
+ new EnvPropertiesKonfigVerdiProvider(),
+ new ApplicationPropertiesKonfigProvider());
+ }
+
+ public static Environment current() {
+ return Init.CURRENT;
+ }
+
+ public Cluster getCluster() {
+ return cluster;
+ }
+
+ public Namespace getNamespace() {
+ return namespace;
+ }
+
+ public Application getApplication() {
+ return application;
+ }
+
+ public ClientId getClientId() {
+ return clientId;
+ }
+
+ public boolean isProd() {
+ return cluster.isProd();
+ }
+
+ public boolean isDev() {
+ return cluster.isDev();
+ }
+
+ public boolean isVTP() {
+ return cluster.isVTP();
+ }
+
+ public boolean isLocal() {
+ return cluster.isLocal();
+ }
+
+ public boolean isFss() {
+ return cluster.isFss();
+ }
+
+ public boolean isGcp() {
+ return cluster.isGcp();
+ }
+
+ public String clusterName() {
+ return cluster.clusterName();
+ }
+
+ public String namespace() {
+ return namespace.getName();
+ }
+
+ public String application() {
+ return application.getName();
+ }
+
+ public String clientId() {
+ return clientId.getClientId();
+ }
+
+ public String imageName() {
+ return imageName;
+ }
+
+ public String getNaisAppName() {
+ return getProperty(NaisProperty.APPLICATION.propertyName(), "vtp");
+ }
+
+ public String getTruststorePath() {
+ return getenv(NaisProperty.TRUSTSTORE_PATH.propertyName());
+ }
+
+ public String getTruststorePassword() {
+ return getenv(NaisProperty.TRUSTSTORE_PASSWORD.propertyName());
+ }
+
+ public Properties getPropertiesWithPrefix(String prefix) {
+ Properties props = new Properties();
+ props.putAll(getProperties(StandardPropertySource.SYSTEM_PROPERTIES).getVerdier());
+ props.putAll(getProperties(StandardPropertySource.ENV_PROPERTIES).getVerdier());
+ props.putAll(getProperties(StandardPropertySource.APP_PROPERTIES).getVerdier());
+
+ var filtered = new Properties();
+ filtered.putAll(props.entrySet()
+ .stream()
+ .filter(k -> k.getKey().toString().startsWith(prefix))
+ .collect(
+ Collectors.toMap(
+ e -> (String) e.getKey(),
+ e -> (String) e.getValue())));
+ return filtered;
+ }
+
+ public PropertySourceMetaData getProperties(StandardPropertySource source) {
+ return propertySources.stream()
+ .filter(p -> p.getSource().equals(source))
+ .findFirst()
+ .map(KonfigVerdiProvider::getAllProperties)
+ .orElseThrow();
+ }
+
+ public List getPropertySources() {
+ return propertySources;
+ }
+
+ public String getProperty(String key, String defaultVerdi) {
+ return getProperty(key, String.class, defaultVerdi);
+ }
+
+ public T getProperty(String key, Class targetType) {
+ return getProperty(key, targetType, null);
+ }
+
+ public String getRequiredProperty(String key) {
+ return getRequiredProperty(key, () -> new IllegalStateException(key + " ble ikke funnet"));
+ }
+
+ public String getRequiredProperty(String key, Supplier extends RuntimeException> exceptionSupplier) {
+ return Optional.ofNullable(getProperty(key))
+ .orElseThrow(exceptionSupplier);
+ }
+
+ public T getRequiredProperty(String key, Class targetType) {
+ return Optional.ofNullable(getProperty(key, targetType))
+ .orElseThrow(() -> new IllegalStateException(key + " ble ikke funnet"));
+ }
+
+ @SuppressWarnings("unchecked")
+ public T getProperty(String key, Class targetType, T defaultVerdi) {
+ var converter = converterFor(targetType);
+ if (converter == null && !targetType.equals(String.class)) {
+ throw new IllegalArgumentException("Konvertering til " + targetType + " er ikke støttet");
+ }
+
+ return propertySources.stream()
+ .filter(s -> s.harVerdi(key))
+ .map(s -> s.getVerdi(key, converter))
+ .filter(Objects::nonNull)
+ .findFirst()
+ .map(v -> (T) v)
+ .orElse(defaultVerdi);
+ }
+
+ public String getProperty(String key) {
+ return getProperty(key, (String) null);
+ }
+
+ private static Converter> converterFor(Class targetType) {
+ try {
+ if (targetType.equals(String.class)) {
+ return construct(NoConverter.class);
+ }
+ if (targetType.equals(Period.class)) {
+ return construct(PeriodConverter.class);
+ }
+ if (targetType.equals(Duration.class)) {
+ return construct(DurationConverter.class);
+ }
+ if (targetType.equals(LocalDate.class)) {
+ return construct(LocalDateConverter.class);
+ }
+ if (targetType.equals(Long.class)) {
+ return construct(LongConverter.class);
+ }
+ if (targetType.equals(Boolean.class) || targetType.equals(boolean.class)) {
+ return construct(BooleanConverter.class);
+ }
+ if (targetType.equals(URI.class)) {
+ return construct(UriConverter.class);
+ }
+ if (targetType.equals(URL.class)) {
+ return construct(UrlConverter.class);
+ }
+ if (targetType.equals(Integer.class) || targetType.equals(int.class)) {
+ return construct(IntegerConverter.class);
+ }
+ if (targetType.equals(Long.class) || targetType.equals(long.class)) {
+ return construct(LongConverter.class);
+ }
+ return null;
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Uventet feil ved konstruksjon av konverter for " + targetType);
+ }
+ }
+
+ private static Converter construct(Class extends Converter> clazz)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
+ return clazz.getDeclaredConstructor().newInstance();
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()
+ + "[cluster=" + cluster
+ + ", namespace=" + namespace
+ + ", propertySources=" + propertySources
+ + "]";
+ }
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdi.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdi.java
new file mode 100644
index 000000000..01c2f1cd9
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdi.java
@@ -0,0 +1,178 @@
+package no.nav.foreldrepenger.konfig;
+
+import jakarta.enterprise.util.AnnotationLiteral;
+import jakarta.enterprise.util.Nonbinding;
+import jakarta.inject.Qualifier;
+import java.lang.annotation.*;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.Period;
+import java.time.format.DateTimeParseException;
+
+@Qualifier
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
+public @interface KonfigVerdi {
+
+ Annotation TYPE_LITERAL = new KonfigVerdiTypeLiteral();
+
+ /* Nøkkel for å slå opp verdi. */
+ @Nonbinding
+ String value() default "";
+
+ @Nonbinding
+ boolean required() default true;
+
+ @Nonbinding
+ String defaultVerdi() default "";
+
+ @Nonbinding
+ String beskrivelse() default "";
+
+ @Nonbinding
+ Class extends Converter>> converter() default NoConverter.class; // NOSONAR
+
+ interface Converter {
+ V tilVerdi(String verdi);
+ }
+
+ class NoConverter implements Converter {
+
+ @Override
+ public String tilVerdi(String verdi) {
+ return verdi;
+ }
+
+ }
+
+ class BooleanConverter implements Converter {
+
+ @Override
+ public Boolean tilVerdi(String verdi) {
+ return verdi == null ? Boolean.FALSE : Boolean.valueOf(verdi);
+ }
+ }
+
+ class IntegerConverter implements Converter {
+
+ @Override
+ public Integer tilVerdi(String verdi) {
+ return verdi == null ? null : Integer.valueOf(verdi);
+ }
+ }
+
+ class LongConverter implements Converter {
+
+ @Override
+ public Long tilVerdi(String verdi) {
+ return verdi == null ? null : Long.valueOf(verdi);
+ }
+ }
+
+ class UriConverter implements Converter {
+
+ @Override
+ public URI tilVerdi(String verdi) {
+ try {
+ return verdi == null ? null : new URI(verdi);
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException(
+ "Ugyldig konfigurasjonsparameter, kan ikke konvertere til java.net.URI: " + verdi, e);
+ }
+ }
+ }
+
+ class UrlConverter implements Converter {
+
+ @Override
+ public URL tilVerdi(String verdi) {
+ try {
+ return verdi == null ? null : new URL(verdi);
+ } catch (MalformedURLException e) {
+ throw new IllegalStateException(
+ "Ugyldig konfigurasjonsparameter, kan ikke konvertere til java.net.URL: " + verdi, e);
+ }
+ }
+ }
+
+ class PeriodConverter implements Converter {
+
+ @Override
+ public Period tilVerdi(String verdi) {
+ try {
+ return verdi == null ? null : Period.parse(verdi);
+ } catch (DateTimeParseException e) {
+ throw new IllegalStateException(
+ "Ugyldig konfigurasjonsparameter, kan ikke konvertere til java.time.Period: " + verdi, e);
+ }
+ }
+ }
+
+ class DurationConverter implements Converter {
+
+ @Override
+ public Duration tilVerdi(String verdi) {
+ try {
+ return verdi == null ? null : Duration.parse(verdi);
+ } catch (DateTimeParseException e) {
+ throw new IllegalStateException(
+ "Ugyldig konfigurasjonsparameter, kan ikke konvertere til java.time.Duration: " + verdi, e);
+ }
+ }
+ }
+
+ class LocalDateConverter implements Converter {
+
+ @Override
+ public LocalDate tilVerdi(String verdi) {
+ try {
+ return verdi == null ? null : LocalDate.parse(verdi);
+ } catch (DateTimeParseException e) {
+ throw new IllegalStateException(
+ "Ugyldig konfigurasjonsparameter, kan ikke konvertere til java.time.LocalDate: " + verdi, e);
+ }
+ }
+ }
+
+ class StringDuplicator implements Converter {
+
+ @Override
+ public String tilVerdi(String verdi) {
+ return verdi + verdi;
+ }
+ }
+
+ class KonfigVerdiTypeLiteral extends AnnotationLiteral implements KonfigVerdi {
+
+ @Override
+ public String value() {
+ return "";
+ }
+
+ @Override
+ public String defaultVerdi() {
+ return "";
+ }
+
+ @Override
+ public boolean required() {
+ return false;
+ }
+
+ @Override
+ public String beskrivelse() {
+ return "";
+ }
+
+ @Override
+ public Class extends Converter>> converter() {
+ return NoConverter.class;
+ }
+ }
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProdusent.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProdusent.java
new file mode 100644
index 000000000..c252d1656
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProdusent.java
@@ -0,0 +1,267 @@
+package no.nav.foreldrepenger.konfig;
+
+import jakarta.annotation.PostConstruct;
+import no.nav.foreldrepenger.konfig.KonfigVerdi.Converter;
+import no.nav.foreldrepenger.konfig.KonfigVerdiProviderOutput.ProviderOutput;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.enterprise.inject.Any;
+import jakarta.enterprise.inject.Instance;
+import jakarta.enterprise.inject.Produces;
+import jakarta.enterprise.inject.spi.Annotated;
+import jakarta.enterprise.inject.spi.InjectionPoint;
+import jakarta.inject.Inject;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.Period;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.regex.Pattern;
+
+/* Producer av konfig verdier. Støtter pluggbart antall providere av konfigurasjonsverdier. */
+@ApplicationScoped
+public class KonfigVerdiProdusent {
+ private static final DefaultValueKonfigProvider DEFAULTVALUEPROVIDER = new DefaultValueKonfigProvider();
+ private static final Pattern SKJUL = Pattern.compile(".*(passw?ord|[k|c]redential|secret).*"); // NOSONAR
+ private static final Logger log = LoggerFactory.getLogger(KonfigVerdiProdusent.class);
+
+ private Instance providerBeans;
+
+ private List providers = new ArrayList<>();
+
+ private Set konfigVerdiReferanser = new ConcurrentSkipListSet<>();
+
+ @SuppressWarnings("rawtypes")
+ private Map, KonfigVerdi.Converter> converters = new ConcurrentHashMap<>();
+
+ KonfigVerdiProdusent() {
+ // for CDI proxy
+ }
+
+ @Inject
+ public KonfigVerdiProdusent(@Any Instance providerBeans) {
+ this.providerBeans = providerBeans;
+ }
+
+ @KonfigVerdi
+ @Produces
+ public String getKonfigVerdiString(InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ return verdi == null ? null : String.valueOf(verdi);
+ }
+
+ @KonfigVerdi
+ @Produces
+ public Boolean getKonfigVerdiBoolean(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ if (verdi == null) {
+ return null; // NOSONAR
+ }
+ return verdi instanceof Boolean value ? value : Boolean.parseBoolean((String) verdi);
+ }
+
+ @KonfigVerdi
+ @Produces
+ public Integer getKonfigVerdiInteger(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ if (verdi == null) {
+ return null;
+ }
+ return verdi instanceof Integer value ? value : Integer.valueOf((String) verdi);
+ }
+
+ @KonfigVerdi
+ @Produces
+ public Period getKonfigVerdiPeriod(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ if (verdi == null) {
+ return null;
+ }
+ return verdi instanceof Period value ? value : Period.parse((String) verdi);
+ }
+
+ @KonfigVerdi
+ @Produces
+ public Duration getKonfigVerdiDuration(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ if (verdi == null) {
+ return null;
+ }
+ return verdi instanceof Duration value ? value : Duration.parse((String) verdi);
+ }
+
+ @KonfigVerdi
+ @Produces
+ public LocalDate getKonfigVerdiLocalDate(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ if (verdi == null) {
+ return null;
+ }
+ return verdi instanceof LocalDate value ? value : LocalDate.parse((String) verdi);
+ }
+
+ @KonfigVerdi
+ @Produces
+ public Long getKonfigVerdiLong(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ if (verdi == null) {
+ return null;
+ }
+ return verdi instanceof Long value ? value : Long.valueOf((String) verdi);
+ }
+
+ /*
+ * Støtter kun URI, ikke URL. Bør unngå URL som konfig verdier pga kjente
+ * problemer med hashcode/equals og ytelse etc.
+ */
+ @KonfigVerdi
+ @Produces
+ public URI getKonfigVerdiUri(final InjectionPoint ip) {
+ Object verdi = getEnkelVerdi(ip);
+ try {
+ if (verdi == null) {
+ return null;
+ }
+ return verdi instanceof URI value ? value : new URI((String) verdi);
+ } catch (URISyntaxException e) {
+ throw new IllegalStateException("KonfigVerdi [" + verdi + "] er ikke en java.net.URI", e);
+ }
+ }
+
+ /*
+ * Returnerer Liste av verdier.
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @KonfigVerdi
+ @Produces
+ public List getKonfigVerdiList(final InjectionPoint ip) {
+ KonfigVerdi annotation = getAnnotation(ip);
+ String key = annotation.value();
+ Converter converter = getConverter(annotation.converter());
+ return getVerdi(ip, annotation, KonfigVerdiProviderOutput.LIST, key, converter);
+ }
+
+ /*
+ * Returnerer Liste av verdier.
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @KonfigVerdi
+ @Produces
+ public Map getKonfigVerdiMap(final InjectionPoint ip) {
+ KonfigVerdi annotation = getAnnotation(ip);
+ String key = annotation.value();
+ Converter converter = getConverter(annotation.converter());
+ return getVerdi(ip, annotation, KonfigVerdiProviderOutput.MAP, key, converter);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Object getEnkelVerdi(final InjectionPoint ip) {
+ KonfigVerdi annotation = getAnnotation(ip);
+ return getVerdi(ip, annotation, KonfigVerdiProviderOutput.SIMPLE);
+ }
+
+ @SuppressWarnings({"rawtypes"})
+ protected T getVerdi(InjectionPoint ip, KonfigVerdi annotation, ProviderOutput outputFunction) {
+ String key = annotation.value();
+ Converter converter = getConverter(annotation.converter());
+ return getVerdi(ip, annotation, outputFunction, key, converter);
+
+ }
+
+ @SuppressWarnings("rawtypes")
+ public T getVerdi(InjectionPoint ip, KonfigVerdi annotation, ProviderOutput outputFunction, String key,
+ Converter converter) {
+ for (KonfigVerdiProvider kvp : providers) {
+ try {
+ if (kvp.harVerdi(key)) {
+ T output = outputFunction.getOutput(kvp, key, converter);
+ sporKonfigVerdier(ip, annotation, output);
+ return output;
+ }
+ } catch (RuntimeException e) {
+ throw new IllegalStateException(
+ "Kunne ikke slå opp verdi for key [" + key + "] fra " + kvp.getClass().getName()
+ + "; InjectionPoint=" + ip,
+ e);
+ }
+ }
+ String defaultVerdi = annotation.defaultVerdi();
+ if (annotation.required() && defaultVerdi.isEmpty()) {
+ throw new IllegalStateException(
+ "Mangler verdi for key(required): " + annotation.value() + "; InjectionPoint=" + ip);
+ } else {
+ if (!defaultVerdi.isEmpty()) {
+ T output = outputFunction.getOutput(DEFAULTVALUEPROVIDER, defaultVerdi, converter);
+ sporKonfigVerdier(ip, annotation, output);
+ return output;
+ }
+ }
+ return null;
+ }
+
+ public void sporKonfigVerdier(InjectionPoint ip, KonfigVerdi annot, T output) {
+
+ Member member = ip.getMember();
+ String name = Constructor.class.isAssignableFrom(member.getClass())
+ ? member.getName()
+ : member.getDeclaringClass().getName() + "#" + member.getName();
+ if (!konfigVerdiReferanser.contains(name)) {
+ String key = annot.value();
+ Object val = SKJUL.matcher(key).matches()
+ ? "********* (skjult)"
+ : output;
+ konfigVerdiReferanser.add(name);
+ log.info("{}: {}=\"{}\" @{}", KonfigVerdi.class.getSimpleName(), key, val, name);
+ }
+ }
+
+ @SuppressWarnings("rawtypes")
+ private KonfigVerdi.Converter getConverter(Class extends KonfigVerdi.Converter>> converterClass) {
+ KonfigVerdi.Converter converter = converters.get(converterClass);
+ if (converter == null) {
+ try {
+ converter = converterClass.getDeclaredConstructor().newInstance();
+ converters.put(converterClass, converter);
+ } catch (ReflectiveOperationException e) {
+ throw new UnsupportedOperationException("Mangler no-arg constructor for klasse: " + converterClass, e);
+ }
+ }
+ return converter;
+
+ }
+
+ protected KonfigVerdi getAnnotation(final InjectionPoint ip) {
+ Annotated annotert = ip.getAnnotated();
+
+ if (annotert == null) {
+ throw new IllegalArgumentException("Mangler annotation KonfigVerdi for InjectionPoint=" + ip);
+ }
+ if (annotert.isAnnotationPresent(KonfigVerdi.class)) {
+ KonfigVerdi annotation = annotert.getAnnotation(KonfigVerdi.class);
+ if (!annotation.value().isEmpty()) {
+ return annotation;
+ }
+ }
+ throw new IllegalStateException("Mangler key. Kan ikke være tom eller null: " + ip.getMember());
+ }
+
+ @PostConstruct
+ public void init() {
+ List alleProviders = new ArrayList<>();
+ for (KonfigVerdiProvider kvp : providerBeans) {
+ alleProviders.add(kvp);
+ }
+ Collections.sort(alleProviders, Comparator.comparingInt(KonfigVerdiProvider::getPrioritet));
+
+ providers.clear();
+ providers.addAll(alleProviders);
+ }
+
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProvider.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProvider.java
new file mode 100644
index 000000000..eae406a4f
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProvider.java
@@ -0,0 +1,27 @@
+package no.nav.foreldrepenger.konfig;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provider som kan slå opp verdi for en angitt key
+ */
+public interface KonfigVerdiProvider {
+
+ /* Get verdi for angitt key. */
+ V getVerdi(String key, KonfigVerdi.Converter converter);
+
+ List getVerdier(String key, KonfigVerdi.Converter converter);
+
+ Map getVerdierAsMap(String key, KonfigVerdi.Converter converter);
+
+ boolean harVerdi(String key);
+
+ StandardPropertySource getSource();
+
+ /* Prioritet rekkefølge. 1 er høyest prioritet. */
+ int getPrioritet();
+
+ PropertySourceMetaData getAllProperties();
+
+}
diff --git a/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProviderOutput.java b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProviderOutput.java
new file mode 100644
index 000000000..54d5ceb43
--- /dev/null
+++ b/felles/konfig/src/main/java/no/nav/foreldrepenger/konfig/KonfigVerdiProviderOutput.java
@@ -0,0 +1,50 @@
+package no.nav.foreldrepenger.konfig;
+
+import no.nav.foreldrepenger.konfig.KonfigVerdi.Converter;
+
+import java.util.List;
+import java.util.Map;
+
+class KonfigVerdiProviderOutput {
+
+ @SuppressWarnings("rawtypes")
+ static final ProviderOutput SIMPLE = new VerdiOutput();
+ @SuppressWarnings("rawtypes")
+ static final ProviderOutput LIST = new ListOutput();
+ @SuppressWarnings("rawtypes")
+ static final ProviderOutput
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
no.nav.foreldrepenger.felles
diff --git a/felles/log/pom.xml b/felles/log/pom.xml
index 5440eab7f..64f501f97 100644
--- a/felles/log/pom.xml
+++ b/felles/log/pom.xml
@@ -18,8 +18,8 @@
jakarta.enterprise.cdi-api
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
io.micrometer
diff --git a/felles/oidc/pom.xml b/felles/oidc/pom.xml
index 38cde811a..367d2a66b 100644
--- a/felles/oidc/pom.xml
+++ b/felles/oidc/pom.xml
@@ -39,8 +39,8 @@
felles-util
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
org.bitbucket.b_c
diff --git a/felles/pom.xml b/felles/pom.xml
index 6b03a50ce..062133095 100644
--- a/felles/pom.xml
+++ b/felles/pom.xml
@@ -14,6 +14,7 @@
testutilities
+ konfig
sikkerhet
oidc
feil
@@ -107,6 +108,12 @@
${project.version}
+
+ no.nav.foreldrepenger.felles
+ felles-konfig
+ ${project.version}
+
+
diff --git a/felles/sikkerhet/pom.xml b/felles/sikkerhet/pom.xml
index d0d33baa5..26032ba05 100644
--- a/felles/sikkerhet/pom.xml
+++ b/felles/sikkerhet/pom.xml
@@ -33,8 +33,8 @@
felles-oidc
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
jakarta.ws.rs
diff --git a/integrasjon/kafka-properties/pom.xml b/integrasjon/kafka-properties/pom.xml
index 139784049..1f9934e2e 100644
--- a/integrasjon/kafka-properties/pom.xml
+++ b/integrasjon/kafka-properties/pom.xml
@@ -15,8 +15,9 @@
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
+ ${project.version}
org.apache.kafka
diff --git a/integrasjon/pom.xml b/integrasjon/pom.xml
index 25c752b18..22912464c 100644
--- a/integrasjon/pom.xml
+++ b/integrasjon/pom.xml
@@ -28,7 +28,7 @@
- 5.8.0
+ 5.9.0
diff --git a/integrasjon/rest-klient/pom.xml b/integrasjon/rest-klient/pom.xml
index 5e0f0904a..3827dcff0 100644
--- a/integrasjon/rest-klient/pom.xml
+++ b/integrasjon/rest-klient/pom.xml
@@ -21,8 +21,9 @@
jakarta.ws.rs-api
- no.nav.foreldrepenger
- konfig
+ no.nav.foreldrepenger.felles
+ felles-konfig
+ ${project.version}
no.nav.foreldrepenger.felles
diff --git a/pom.xml b/pom.xml
index 087119be8..ed0cf2083 100644
--- a/pom.xml
+++ b/pom.xml
@@ -7,7 +7,7 @@
no.nav.foreldrepenger.felles
fp-bom
- 1.0.5
+ 2.0.0
felles-root
@@ -18,7 +18,7 @@
felles
integrasjon
-
+
${project.artifactId}
@@ -33,7 +33,7 @@
no.nav.foreldrepenger.felles
fp-bom
- 1.0.5
+ 2.0.0
import
pom