All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.gematik.prepare.pooling.Pooler Maven / Gradle / Ivy

/*
 * Copyright 2023 gematik GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.gematik.prepare.pooling;

import static de.gematik.prepare.pooling.strategies.MatchStrategy.MATCHING;
import static de.gematik.utils.Utils.getItemsToCombine;
import static java.lang.String.format;

import de.gematik.combine.model.CombineItem;
import de.gematik.prepare.PrepareItemsConfig;
import de.gematik.prepare.PrepareItemsMojo;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.apache.maven.plugin.MojoExecutionException;

@NoArgsConstructor
public class Pooler {

  @SuppressWarnings("java:S2245")
  private final Random random = new Random();

  @Setter private PrepareItemsConfig config;

  public Pooler(PrepareItemsConfig config) {
    this.config = config;
  }

  public List pool() throws MojoExecutionException {
    List allCombineItems =
        getItemsToCombine(
            new File(config.getCombineItemsFile()), PrepareItemsMojo.getInstance(), false);
    allCombineItems.removeAll(
        allCombineItems.stream()
            .filter(
                e -> getMatcher(config.getExcludedGroups()).order(e.getGroups()).equals(MATCHING))
            .collect(Collectors.toList()));
    Set items = getNeededItemsFromGroup(allCombineItems);
    if (config.getPoolSize() <= 0 && !items.isEmpty()) {
      return new ArrayList<>(items);
    }

    allCombineItems.removeAll(items);
    doChecks(allCombineItems, items);

    return new ArrayList<>(fillUpList(allCombineItems, items));
  }

  private Set getNeededItemsFromGroup(final List allCombineItems)
      throws MojoExecutionException {
    Set items = new HashSet<>();

    for (PoolGroup poolGroup : config.getPoolGroups()) {
      items.addAll(getRequestedAmountFromPoolGroup(poolGroup, allCombineItems));
    }
    return items;
  }

  private Collection getRequestedAmountFromPoolGroup(
      PoolGroup poolGroup, List allCombineItems) throws MojoExecutionException {

    GroupMatcher matcher = getMatcher(poolGroup);
    List selectedItems = new ArrayList<>();

    List matchingItems = matcher.getAllItemsMatching(allCombineItems);
    if (matchingItems.isEmpty()) {
      throw new MojoExecutionException(
          "Could not find at least one match for poolgroup: " + poolGroup);
    }
    List matchingGroups = matcher.getAllMatchingGroups(matchingItems);

    if (matchingGroups.size() < poolGroup.getAmount()) {
      throw new MojoExecutionException(
          format(
              "Requested %s for group(s) %s but only found %s matching group(s) (%s) with matching strategy %s",
              poolGroup.getAmount(),
              poolGroup.getGroupPattern(),
              matchingGroups.size(),
              matchingGroups,
              poolGroup.getStrategy()));
    }
    if (poolGroup.getAmount() < 1) {
      return allCombineItems.stream()
          .filter(item -> matcher.order(item).equals(MATCHING))
          .collect(Collectors.toSet());
    }
    IntStream.range(0, poolGroup.getAmount())
        .forEach(
            i -> {
              String randomGroup = selectRandomGroup(matchingItems, matcher);
              List randomSelectedItems =
                  matchingItems.stream()
                      .filter(item -> item.getGroups().contains(randomGroup))
                      .collect(Collectors.toList());
              matchingItems.removeAll(randomSelectedItems);
              selectedItems.addAll(randomSelectedItems);
            });
    return selectedItems;
  }

  private String selectRandomGroup(List matchingItems, GroupMatcher matcher) {
    List validGroups = matcher.getAllMatchingGroups(matchingItems);
    return validGroups.get(random.nextInt(validGroups.size()));
  }

  private Set fillUpList(List leftItems, Set items) {
    if (config.getPoolSize() < 1) {
      return new HashSet<>(leftItems);
    }
    while (countGroups(items) < config.getPoolSize() || items.size() < config.getPoolSize()) {
      CombineItem randomItem = leftItems.get(random.nextInt(leftItems.size()));
      if (randomItem.getGroups().isEmpty()) {
        items.add(randomItem);
        leftItems.remove(randomItem);
        continue;
      }
      String randomGroup =
          new ArrayList<>(randomItem.getGroups())
              .get(random.nextInt(randomItem.getGroups().size()));
      List newItems =
          leftItems.stream()
              .filter(i -> getMatcher(List.of(randomGroup)).order(i).equals(MATCHING))
              .collect(Collectors.toList());
      items.addAll(newItems);
      leftItems.removeAll(newItems);
      config
          .getPoolGroups()
          .add(new PoolGroup(List.of(randomGroup), 0, config.getDefaultMatchStrategy()));
    }
    return items;
  }

  private void doChecks(List leftItems, Set items)
      throws MojoExecutionException {
    if (countGroups(leftItems) + countGroups(items) < config.getPoolSize()) {
      throw new MojoExecutionException(
          "PoolSize to high! Could not find sufficient item-groups to fulfill request");
    }
  }

  private long countGroups(Collection itemList) {
    long itemsWithoutGroup = itemList.stream().filter(i -> i.getGroups().isEmpty()).count();
    long sumGroupsFromItems =
        itemList.stream()
            .map(CombineItem::getGroups)
            .flatMap(Collection::stream)
            .collect(Collectors.toSet())
            .size();
    return sumGroupsFromItems + itemsWithoutGroup;
  }

  private GroupMatcher getMatcher(PoolGroup poolGroup) {
    return poolGroup.getStrategy() == null
        ? getMatcher(poolGroup.getGroupPattern())
        : getMatcher(poolGroup.getStrategy(), poolGroup.getGroupPattern());
  }

  private GroupMatcher getMatcher(List groups) {
    return getMatcher(config.getDefaultMatchStrategy(), groups);
  }

  private GroupMatcher getMatcher(GroupMatchStrategyType strategy, List groups) {
    return new GroupMatcher(groups, strategy);
  }

  public boolean matchAny(String s) {
    return config.getPoolGroups().stream()
        .anyMatch(poolGroup -> !getMatcher(poolGroup).getAllMatchingGroups(Set.of(s)).isEmpty());
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy