001/* 002 * SPDX-License-Identifier: Apache-2.0 003 * 004 * Copyright 2024-2026 The Enola <https://enola.dev> Authors 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package dev.enola.data; 019 020import com.google.common.collect.ImmutableCollection; 021import com.google.common.collect.ImmutableList; 022import com.google.common.collect.ImmutableSet; 023import com.google.common.collect.ImmutableSortedMap; 024 025import dev.enola.common.Builder; 026 027import org.jspecify.annotations.Nullable; 028 029import java.util.HashMap; 030import java.util.Map; 031 032/** 033 * RepositoryBuilder builds immutable {@link Repository} instances. 034 * 035 * <p>This Builder class itself is NOT thread-safe. The {@link Repository} returned by its {@link 036 * #build()} however is thread-safe (simply because it's immutable). Use {@link MemoryRepositoryRW} 037 * for a thread-safe {@link Store}. 038 */ 039public abstract class RepositoryBuilder<T> extends AbstractMapRepositoryRW<T> 040 implements RepositoryRW<T>, Builder<Repository<T>> { 041 042 private final Map<String, T> map = new HashMap<>(); 043 044 protected RepositoryBuilder(ImmutableList<Trigger<? extends T>> triggers) { 045 super(triggers); 046 } 047 048 // TODO @Deprecated 049 protected RepositoryBuilder() { 050 this(ImmutableList.of()); 051 } 052 053 @Override 054 protected Map<String, T> map() { 055 return map; 056 } 057 058 @Override 059 public RepositoryBuilder<T> store(T item) { 060 super.store(item); 061 return this; 062 } 063 064 @Override 065 public RepositoryBuilder<T> storeAll(Iterable<T> items) { // skipcq: JAVA-W1016 066 super.storeAll(items); 067 return this; 068 } 069 070 @Override 071 public Repository<T> build() { 072 return new RepositoryImpl<>(buildMap()); 073 } 074 075 protected ImmutableSortedMap<String, T> buildMap() { 076 return ImmutableSortedMap.<String, T>naturalOrder().putAll(map).buildOrThrow(); 077 } 078 079 protected <O> O require(O what, String identification) { 080 if (what == null) throw new IllegalArgumentException("Missing required: " + identification); 081 if (what instanceof String whatString) { 082 if (whatString.trim().isEmpty()) 083 throw new IllegalArgumentException("Empty: " + identification); 084 } 085 return what; 086 } 087 088 protected static class RepositoryImpl<T> implements Repository<T> { 089 private final ImmutableSortedMap<String, T> items; 090 091 protected RepositoryImpl(ImmutableSortedMap<String, T> items) { 092 this.items = items; 093 } 094 095 @Override 096 public ImmutableSet<String> listIRI() { 097 return items.keySet(); 098 } 099 100 @Override 101 public @Nullable T get(String iri) { 102 return items.get(iri); 103 } 104 105 @Override 106 public ImmutableCollection<T> list() { 107 return items.values(); 108 } 109 110 @Override 111 public String toString() { 112 return "RepositoryImpl{" + "items=" + items.keySet() + '}'; 113 } 114 } 115}