/* * This file is part of LanternServer, licensed under the MIT License (MIT). * * Copyright (c) LanternPowered <https://www.lanternpowered.org> * Copyright (c) SpongePowered <https://www.spongepowered.org> * Copyright (c) contributors * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the Software), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.lanternpowered.server.data.value; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableSet; import org.lanternpowered.server.data.value.processor.ValueProcessor; import org.spongepowered.api.data.DataTransactionResult; import org.spongepowered.api.data.key.Key; import org.spongepowered.api.data.value.BaseValue; import org.spongepowered.api.data.value.BoundedValue; import org.spongepowered.api.data.value.ValueContainer; import org.spongepowered.api.data.value.immutable.ImmutableBoundedValue; import org.spongepowered.api.data.value.immutable.ImmutableValue; import org.spongepowered.api.data.value.mutable.MutableBoundedValue; import org.spongepowered.api.data.value.mutable.Value; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import javax.annotation.Nullable; public interface AbstractValueContainer<C extends ValueContainer<C>, H extends ValueContainer<?>> extends IValueContainer<C> { /** * Some {@link ValueProcessor}'s may want to depend on the fact that * a specific {@link Key} is applicable or attached to a {@link ValueContainer}. * * This class will represent a {@link Value} that is attached to a * specific {@link ValueContainer}. */ class ElementHolderKeyRegistrationImpl<V extends BaseValue<E>, E> extends SimpleKeyRegistration.SingleProcessor<V, E> implements ElementHolderKeyRegistration<V, E> { private @Nullable E value; ElementHolderKeyRegistrationImpl(Key<? extends V> key) { super(key); } @Nullable @Override public synchronized E set(@Nullable E value) { final E oldValue = this.value; this.value = value; return oldValue; } @Nullable @Override public synchronized E get() { return this.value; } @Override public ElementHolderKeyRegistration<V, E> addValueProcessor(ValueProcessor<V, E> valueProcessor) { super.addValueProcessor(valueProcessor); return this; } @Override public ElementHolderKeyRegistration<V, E> applyValueProcessor(Consumer<ValueProcessor.Builder<V, E>> builderConsumer) { super.applyValueProcessor(builderConsumer); return this; } @Override public ElementHolderKeyRegistration<V, E> addElementChangeListener(ElementHolderChangeListener listener) { super.addElementChangeListener(listener); return this; } @Override public ElementHolderKeyRegistration<V, E> applyAttachedValueProcessor( Consumer<ValueProcessor.AttachedElementBuilder<V, E>> attachedElementBuilderConsumer) { final ValueProcessor.AttachedElementBuilder<V, E> builder = ValueProcessor.attachedElementBuilder(); checkNotNull(attachedElementBuilderConsumer, "attachedElementBuilderConsumer").accept(builder); return addValueProcessor(builder.build()); } } /** * Whether all the {@link Key}s in this container should be registered * before they can be offered/retrieved. * * @return requires key registration */ default boolean requiresKeyRegistration() { return false; } /** * Gets the raw list with all the custom value containers, * this may be null if custom data isn't supported. * * @return The raw value containers */ @Nullable default Map<Class<?>, H> getRawAdditionalContainers() { return null; } /** * Gets the internal map that is used to hold the value's by their key. * * @return the value by key map */ Map<Key<?>, KeyRegistration> getRawValueMap(); @SuppressWarnings("unchecked") @Nullable default <V extends BaseValue<E>, E> KeyRegistration<V, E> getKeyRegistration(Key<? extends BaseValue<E>> key) { return getRawValueMap().get(key); } @SuppressWarnings("unchecked") @Override default boolean supports(Key<?> key) { checkNotNull(key, "key"); // Check the local key registration final KeyRegistration<?, ?> localKeyRegistration = getKeyRegistration((Key) key); if (localKeyRegistration == null) { if (requiresKeyRegistration()) { return false; } } else if (!localKeyRegistration.getValueProcessors().isEmpty()) { return true; } // Check the global key registrations final KeyRegistration<?, ?> keyRegistration = LanternValueFactory.getInstance().getKeyRegistration((Key) key); if (keyRegistration != null) { for (ValueProcessor<?,?> valueProcessor : keyRegistration.getValueProcessors()) { if (valueProcessor.getApplicableTester().test((Key) key, this)) { return true; } } } // Use the global processor if (localKeyRegistration != null && localKeyRegistration instanceof ElementHolder) { return true; } // Check for the custom value containers final Map<Class<?>, H> valueContainers = getRawAdditionalContainers(); // Custom data is supported by this container if (valueContainers != null) { for (H valueContainer : valueContainers.values()) { if (valueContainer.supports(key)) { return true; } } } return false; } @SuppressWarnings("unchecked") default <E> Optional<E> getWith(Key<? extends BaseValue<E>> key, ValueProcessor<BaseValue<E>, E> processor) { return (Optional) ((BiFunction) processor.getRetrieveHandler()).apply(key, this); } @SuppressWarnings("unchecked") @Override default <E> Optional<E> get(Key<? extends BaseValue<E>> key) { checkNotNull(key, "key"); // Check the local key registration final KeyRegistration<BaseValue<E>, E> localKeyRegistration = getKeyRegistration(key); if (localKeyRegistration == null) { if (requiresKeyRegistration()) { return Optional.empty(); } } else { final List<ValueProcessor<BaseValue<E>, E>> processors = localKeyRegistration.getValueProcessors(); if (!processors.isEmpty()) { return getWith(key, processors.get(0)); } } // Check the global key registrations final KeyRegistration<BaseValue<E>, E> keyRegistration = LanternValueFactory.getInstance().getKeyRegistration(key); if (keyRegistration != null) { for (ValueProcessor<BaseValue<E>, E> valueProcessor : keyRegistration.getValueProcessors()) { if (valueProcessor.getApplicableTester().test((Key) key, this)) { return getWith(key, valueProcessor); } } } // Use the global processor if (localKeyRegistration != null && localKeyRegistration instanceof ElementHolder) { return getWith(key, ValueProcessor.getDefaultAttachedValueProcessor()); } // Check for the custom value containers final Map<Class<?>, H> valueContainers = getRawAdditionalContainers(); // Custom data is supported by this container if (valueContainers != null) { for (H valueContainer : valueContainers.values()) { if (valueContainer.supports(key)) { return valueContainer.get(key); } } } return Optional.empty(); } @SuppressWarnings("unchecked") default <E, V extends BaseValue<E>> Optional<V> getValueWith(Key<? extends BaseValue<E>> key, ValueProcessor<BaseValue<E>, E> processor) { return (Optional) ((BiFunction) processor.getValueRetrieveHandler()).apply(key, this); } @SuppressWarnings("unchecked") @Override default <E, V extends BaseValue<E>> Optional<V> getValue(Key<V> key) { checkNotNull(key, "key"); // Check the local key registration final KeyRegistration<BaseValue<E>, E> localKeyRegistration = getKeyRegistration(key); if (localKeyRegistration == null) { if (requiresKeyRegistration()) { return Optional.empty(); } } else { final List<ValueProcessor<BaseValue<E>, E>> processors = localKeyRegistration.getValueProcessors(); if (!processors.isEmpty()) { return getValueWith(key, processors.get(0)); } } // Check the global key registrations final KeyRegistration<BaseValue<E>, E> keyRegistration = LanternValueFactory.getInstance().getKeyRegistration(key); if (keyRegistration != null) { for (ValueProcessor<BaseValue<E>, E> valueProcessor : keyRegistration.getValueProcessors()) { if (valueProcessor.getApplicableTester().test((Key) key, this)) { return getValueWith(key, valueProcessor); } } } // Use the global processor if (localKeyRegistration != null && localKeyRegistration instanceof ElementHolder) { return getValueWith(key, ValueProcessor.getDefaultAttachedValueProcessor()); } // Check for the custom data manipulators final Map<Class<?>, H> valueContainers = getRawAdditionalContainers(); // Custom data is supported by this container if (valueContainers != null) { for (H valueContainer : valueContainers.values()) { if (valueContainer.supports(key)) { return valueContainer.getValue(key); } } } return Optional.empty(); } @Override default Set<Key<?>> getKeys() { final ImmutableSet.Builder<Key<?>> keys = ImmutableSet.builder(); keys.addAll(getRawValueMap().keySet()); final Map<Class<?>, ? extends H> manipulators = getRawAdditionalContainers(); if (manipulators != null) { manipulators.values().forEach(manipulator -> keys.addAll(manipulator.getKeys())); } return keys.build(); } @SuppressWarnings("unchecked") @Override default Set<ImmutableValue<?>> getValues() { final ImmutableSet.Builder<ImmutableValue<?>> values = ImmutableSet.builder(); for (Map.Entry<Key<?>, KeyRegistration> entry : getRawValueMap().entrySet()) { final Key key = entry.getKey(); final Optional<BaseValue> optValue = getValue(key); if (optValue.isPresent()) { values.add(ValueHelper.toImmutable(optValue.get())); } } final Map<Class<?>, H> valueContainers = getRawAdditionalContainers(); // Custom data is supported by this container if (valueContainers != null) { for (H valueContainer : valueContainers.values()) { values.addAll(valueContainer.getValues()); } } return values.build(); } @SuppressWarnings("unchecked") @Override default <E> ElementHolder<E> getElementHolder(Key<? extends BaseValue<E>> key) { final Object object = getRawValueMap().get(checkNotNull(key, "key")); if (object instanceof ElementHolder) { return (ElementHolder<E>) object; } return null; } @Override default <V extends BaseValue<E>, E> ElementHolderKeyRegistration<V, E> registerKey(Key<? extends V> key, @Nullable E defaultValue) { checkNotNull(key, "key"); final Map<Key<?>, KeyRegistration> map = getRawValueMap(); checkArgument(!map.containsKey(key), "The specified key (%s) is already registered.", key); final ElementHolderKeyRegistrationImpl<V, E> holder = new ElementHolderKeyRegistrationImpl<>(key); holder.set(defaultValue); map.put(key, holder); return holder; } @Override default <V extends BaseValue<E>, E> ElementHolderKeyRegistration<V, E> registerKey(Key<? extends V> key) { return registerKey(key, null); } default <V extends BoundedValue<E>, E extends Comparable<E>> ElementHolderKeyRegistration<V, E> registerKeySupplied(Key<? extends V> key, E defaultValue, Supplier<E> minimumSupplier, Supplier<E> maximumSupplier) { // TODO: Permit absent bounded values final ElementHolderKeyRegistration<V, E> registration = registerKey(key, defaultValue); final boolean immutable = key.getValueToken().getRawType().isAssignableFrom(ImmutableValue.class); registration.applyValueProcessor(builder -> builder.offerHandler((key1, valueContainer, element) -> { final E minimum = minimumSupplier.get(); final E maximum = maximumSupplier.get(); final ImmutableBoundedValue<E> newValue = LanternValueFactory.boundedBuilder(key) .actualValue(element) .defaultValue(defaultValue) .maximum(maximum) .minimum(minimum) .build().asImmutable(); if (element.compareTo(maximum) > 0 || element.compareTo(minimum) < 0) { return DataTransactionResult.errorResult(newValue); } final E oldElement = registration.set(element); if (oldElement == null) { return DataTransactionResult.successResult(newValue); } return DataTransactionResult.successReplaceResult(newValue, LanternValueFactory.boundedBuilder(key) .actualValue(oldElement) .defaultValue(defaultValue) .maximum(maximum) .minimum(minimum) .build().asImmutable()); }).retrieveHandler((key1, valueContainer) -> { E element = registration.get(); if (element == null) { return Optional.empty(); } else { final E minimum = minimumSupplier.get(); if (element.compareTo(minimum) < 0) { registration.set(minimum); element = minimum; } else { final E maximum = maximumSupplier.get(); if (element.compareTo(minimum) > 0) { registration.set(maximum); element = maximum; } } return Optional.of(element); } }).valueRetrieveHandler((key1, valueContainer) -> { E element = registration.get(); if (element == null) { return Optional.empty(); } else { final E minimum = minimumSupplier.get(); final E maximum = maximumSupplier.get(); if (element.compareTo(minimum) < 0) { registration.set(minimum); element = minimum; } else if (element.compareTo(minimum) > 0) { registration.set(maximum); element = maximum; } final MutableBoundedValue<E> value = LanternValueFactory.boundedBuilder(key) .actualValue(element) .defaultValue(defaultValue) .maximum(maximum) .minimum(minimum) .build(); //noinspection unchecked return Optional.of((V) (immutable ? value.asImmutable() : value)); } }).removeHandler((key1, valueContainer) -> { E element = registration.get(); if (element == null) { return DataTransactionResult.failNoData(); } final E minimum = minimumSupplier.get(); final E maximum = maximumSupplier.get(); return DataTransactionResult.failResult(LanternValueFactory.boundedBuilder(key) .actualValue(element) .defaultValue(defaultValue) .maximum(maximum) .minimum(minimum) .build().asImmutable()); })); return registration; } @Override default <V extends BoundedValue<E>, E extends Comparable<E>> ElementHolderKeyRegistration<V, E> registerKey(Key<? extends V> key, E defaultValue, E minimum, E maximum) { return registerKeySupplied(key, defaultValue, () -> minimum, () -> maximum); } @Override default <V extends BoundedValue<E>, E extends Comparable<E>> ElementHolderKeyRegistration<V, E> registerKey(Key<? extends V> key, E defaultValue, Key<? extends BaseValue<E>> minimum, Key<? extends BaseValue<E>> maximum) { return registerKeySupplied(key, defaultValue, () -> get(minimum).get(), () -> get(maximum).get()); } @Override default <V extends BoundedValue<E>, E extends Comparable<E>> ElementHolderKeyRegistration<V, E> registerKey(Key<? extends V> key, E defaultValue, E minimum, Key<? extends BaseValue<E>> maximum) { return registerKeySupplied(key, defaultValue, () -> minimum, () -> get(maximum).get()); } @Override default <V extends BoundedValue<E>, E extends Comparable<E>> ElementHolderKeyRegistration<V, E> registerKey(Key<? extends V> key, E defaultValue, Key<? extends BaseValue<E>> minimum, E maximum) { return registerKeySupplied(key, defaultValue, () -> get(minimum).get(), () -> maximum); } @Override default <V extends BaseValue<E>, E> KeyRegistration<V, E> registerProcessorKey(Key<? extends V> key) { checkNotNull(key, "key"); final Map<Key<?>, KeyRegistration> map = getRawValueMap(); checkArgument(!map.containsKey(key), "The specified key (%s) is already registered.", key); final KeyRegistration<V, E> holder = new SimpleKeyRegistration.SingleProcessor<>(key); map.put(key, holder); return holder; } default Map<Key<?>, KeyRegistration> copyRawValueMap() { final Map<Key<?>, KeyRegistration> copy = new HashMap<>(); final Map<Key<?>, KeyRegistration> map = getRawValueMap(); for (Map.Entry<Key<?>, KeyRegistration> entry : map.entrySet()) { final KeyRegistration registration = entry.getValue(); KeyRegistration registrationCopy; if (registration instanceof ElementHolderKeyRegistration) { //noinspection unchecked final ElementHolderKeyRegistrationImpl element = new ElementHolderKeyRegistrationImpl(registration.getKey()); element.value = ((ElementHolderKeyRegistration) registration).get(); registrationCopy = element; } else { registrationCopy = ((SimpleKeyRegistration.SingleProcessor) registration).copy(); } copy.put(entry.getKey(), registrationCopy); } return copy; } @Nullable default Map<Class<?>, H> copyRawAdditionalManipulators() { return copyRawAdditionalManipulators(HashMap::new); } @SuppressWarnings("unchecked") @Nullable default Map<Class<?>, H> copyRawAdditionalManipulators(Supplier<Map<Class<?>, ? extends H>> supplier) { final Map<Class<?>, H> map = getRawAdditionalContainers(); if (map == null) { return null; } final Map copy = supplier.get(); for (Map.Entry<Class<?>, H> entry : map.entrySet()) { copy.put(entry.getKey(), entry.getValue().copy()); } return copy; } @Nullable default <R extends ValueContainer<?>> Map<Class<?>, R> copyConvertedRawAdditionalManipulators(Function<H, R> converter) { // No method reference here, thanks intellij... //noinspection Convert2MethodRef return copyConvertedRawAdditionalManipulators(converter, () -> new HashMap<>()); } @SuppressWarnings("unchecked") @Nullable default <R extends ValueContainer<?>> Map<Class<?>, R> copyConvertedRawAdditionalManipulators(Function<H, R> converter, Supplier<Map<Class<?>, R>> supplier) { final Map<Class<?>, H> map = getRawAdditionalContainers(); if (map == null) { return null; } final Map copy = supplier.get(); for (Map.Entry<Class<?>, H> entry : map.entrySet()) { copy.put(entry.getKey(), ((Function) converter).apply(entry.getValue())); } return copy; } }