tech.jhipster.lite.module.domain.landscape.JHipsterLandscapeLevels Maven / Gradle / Ivy
package tech.jhipster.lite.module.domain.landscape;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import tech.jhipster.lite.module.domain.JHipsterFeatureSlug;
import tech.jhipster.lite.module.domain.JHipsterSlug;
import tech.jhipster.lite.module.domain.resource.JHipsterModuleResource;
import tech.jhipster.lite.module.domain.resource.JHipsterModulesResources;
import tech.jhipster.lite.shared.error.domain.Assert;
public record JHipsterLandscapeLevels(Collection levels) {
public JHipsterLandscapeLevels(Collection levels) {
Assert.notEmpty("levels", levels);
this.levels = Collections.unmodifiableCollection(levels);
}
static JHipsterLandscapeLevelsBuilder builder() {
return new JHipsterLandscapeLevelsBuilder();
}
public Collection get() {
return levels();
}
public Stream stream() {
return levels().stream();
}
static class JHipsterLandscapeLevelsBuilder {
private final Map> features = new ConcurrentHashMap<>();
private final Collection modules = new ArrayList<>();
JHipsterLandscapeLevelsBuilder resources(JHipsterModulesResources resources) {
Assert.notNull("resources", resources);
resources.stream().forEach(this::append);
return this;
}
private JHipsterLandscapeLevelsBuilder append(JHipsterModuleResource resource) {
Assert.notNull("resource", resource);
resource.organization().feature().ifPresentOrElse(addFeature(resource), addModule(resource));
return this;
}
private Consumer addFeature(JHipsterModuleResource resource) {
return feature -> features.computeIfAbsent(feature, newArrayList()).add(landscapeModule(resource));
}
private Function> newArrayList() {
return key -> new ArrayList<>();
}
private Runnable addModule(JHipsterModuleResource resource) {
return () -> modules.add(landscapeModule(resource));
}
private static JHipsterLandscapeModule landscapeModule(JHipsterModuleResource resource) {
return JHipsterLandscapeModule.builder()
.module(resource.slug())
.operation(resource.apiDoc().operation())
.propertiesDefinition(resource.propertiesDefinition())
.dependencies(resource.organization().dependencies());
}
public JHipsterLandscapeLevels build() {
List elements = Stream.concat(features.entrySet().stream().map(toFeature()), modules.stream()).toList();
JHipsterLandscapeLevelsDispatcher dispatcher = new JHipsterLandscapeLevelsDispatcher(elements);
dispatcher.buildRoot();
while (dispatcher.hasRemainingElements()) {
dispatcher.dispatchNextLevel();
}
return new JHipsterLandscapeLevels(dispatcher.levels());
}
private Function>, JHipsterLandscapeFeature> toFeature() {
return entry -> new JHipsterLandscapeFeature(entry.getKey(), entry.getValue());
}
}
private static class JHipsterLandscapeLevelsDispatcher {
private final List levels = new ArrayList<>();
private List elementsToDispatch;
public JHipsterLandscapeLevelsDispatcher(List elements) {
elementsToDispatch = elements;
}
public void buildRoot() {
List rootElements = levelElements(withoutDependencies());
if (rootElements.isEmpty()) {
throw InvalidLandscapeException.missingRootElement();
}
appendLevel(rootElements);
}
private Predicate withoutDependencies() {
return element -> element.dependencies().isEmpty();
}
public boolean hasRemainingElements() {
return !elementsToDispatch.isEmpty();
}
public void dispatchNextLevel() {
Set knownSlugs = knownSlugs();
List levelElements = levelElements(withAllKnownDependencies(knownSlugs));
if (levelElements.isEmpty()) {
throw InvalidLandscapeException.unknownDependency(
knownSlugs,
elementsToDispatch.stream().map(JHipsterLandscapeElement::slug).toList()
);
}
appendLevel(levelElements);
}
private List levelElements(Predicate condition) {
return elementsToDispatch.stream().filter(condition).toList();
}
private Predicate withAllKnownDependencies(Set knownSlugs) {
return element ->
knownSlugs.containsAll(
element.dependencies().stream().flatMap(JHipsterLandscapeDependencies::stream).map(JHipsterLandscapeDependency::slug).toList()
);
}
private Set knownSlugs() {
return levels.stream().flatMap(JHipsterLandscapeLevel::slugs).collect(Collectors.toSet());
}
private void appendLevel(List elements) {
updateElementsToDispatch(elements);
levels.add(new JHipsterLandscapeLevel(elements));
}
private void updateElementsToDispatch(List elements) {
elementsToDispatch = elementsToDispatch.stream().filter(element -> !elements.contains(element)).toList();
}
public Collection levels() {
return levels;
}
}
}