org.neo4j.gds.configuration.LimitsConfiguration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of defaults-and-limits-configuration Show documentation
Show all versions of defaults-and-limits-configuration Show documentation
Neo4j Graph Data Science :: Defaults and Limits Configuration
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package org.neo4j.gds.configuration;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
public class LimitsConfiguration {
/**
* A JVM-wide singleton we can use to store the limits configuration. Lifecycle of this singleton matches that of
* the data it holds - it starts empty and dies when JVM exists.
*/
public static final LimitsConfiguration Instance = new LimitsConfiguration(
new HashMap<>(),
new HashMap<>()
);
/**
* This is a handy singleton for when you need to satisfy a requirement for the configuration, but want to ignore
* limits entirely.
*/
public static final LimitsConfiguration Empty = new LimitsConfiguration(
Collections.emptyMap(),
Collections.emptyMap()
);
private final Map globalLimits;
private final Map> personalLimits;
public LimitsConfiguration(Map globalLimits, Map> personalLimits) {
this.globalLimits = globalLimits;
this.personalLimits = personalLimits;
}
public Set validate(Map configuration, String username) {
var limitViolations = new HashSet();
for (Map.Entry inputParameter : configuration.entrySet()) {
var key = inputParameter.getKey();
var value = inputParameter.getValue();
// personal limits take precedence
if (personalLimits.getOrDefault(username, Collections.emptyMap()).containsKey(key)) {
Limit limit = personalLimits.get(username).get(key);
if (limit.isViolated(value)) {
limitViolations.add(new LimitViolation(limit.asErrorMessage(key, value)));
continue; // we found a violation; skip to next parameter
}
}
// global limits come second
if (!globalLimits.containsKey(key)) continue;
var limit = globalLimits.get(key);
if (limit.isViolated(value)) {
var limitViolation = new LimitViolation(limit.asErrorMessage(key, value));
limitViolations.add(limitViolation);
}
}
return limitViolations;
}
public Map list(Optional username, Optional key) {
var limits = startWithGlobalLimits();
overlayPersonalLimitsIfApplicable(username, limits);
if (key.isEmpty()) return limits;
if (!limits.containsKey(key.get())) return Collections.emptyMap(); // done because value does not exist for key
Object value = limits.get(key.get());
return Map.of(key.get(), value);
}
public void set(String key, Object value, Optional username) {
var valueAsLimit = LimitFactory.create(value);
if (username.isPresent()) {
personalLimits.putIfAbsent(username.get(), new HashMap<>()); // lazy initialisation
personalLimits.get(username.get()).put(key, valueAsLimit);
} else {
globalLimits.put(key, valueAsLimit);
}
}
private Map startWithGlobalLimits() {
return globalLimits.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getValue()));
}
private void overlayPersonalLimitsIfApplicable(Optional username, Map defaults) {
username.ifPresent(s -> personalLimits.getOrDefault(s, Collections.emptyMap())
.forEach((k, v) -> defaults.put(k, v.getValue())));
}
}