/* * 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.mutable; import static com.google.common.base.Preconditions.checkNotNull; import org.lanternpowered.server.data.value.AbstractValueContainer; import org.lanternpowered.server.data.value.ElementHolder; import org.lanternpowered.server.data.value.KeyRegistration; import org.lanternpowered.server.data.value.LanternValueFactory; import org.lanternpowered.server.data.value.ValueHelper; import org.lanternpowered.server.data.value.processor.ValueProcessor; import org.lanternpowered.server.util.functions.TriFunction; import org.spongepowered.api.data.DataTransactionResult; import org.spongepowered.api.data.key.Key; import org.spongepowered.api.data.manipulator.DataManipulator; import org.spongepowered.api.data.merge.MergeFunction; import org.spongepowered.api.data.value.BaseValue; import org.spongepowered.api.data.value.ValueContainer; import org.spongepowered.api.data.value.immutable.ImmutableValue; import org.spongepowered.api.data.value.mutable.CompositeValueStore; import org.spongepowered.api.event.cause.Cause; import java.util.List; import java.util.Map; import java.util.function.BiFunction; public interface AbstractCompositeValueStore<S extends CompositeValueStore<S, H>, H extends ValueContainer<?>> extends AbstractValueContainer<S, H>, CompositeValueStore<S, H> { @SuppressWarnings("unchecked") default <E> DataTransactionResult offerWith(Key<? extends BaseValue<E>> key, E element, ValueProcessor<BaseValue<E>, E> processor) { return (DataTransactionResult) ((TriFunction) processor.getOfferHandler()).apply(key, this, element); } @Override default <E> DataTransactionResult offer(Key<? extends BaseValue<E>> key, E value, Cause cause) { return offer(key, value); } @SuppressWarnings("unchecked") @Override default <E> DataTransactionResult offer(Key<? extends BaseValue<E>> key, E element) { checkNotNull(key, "key"); checkNotNull(element, "element"); // Check the local key registration final KeyRegistration<BaseValue<E>, E> localKeyRegistration = getKeyRegistration(key); if (localKeyRegistration == null) { if (requiresKeyRegistration()) { return DataTransactionResult.failNoData(); } } else { final List<ValueProcessor<BaseValue<E>, E>> processors = localKeyRegistration.getValueProcessors(); if (!processors.isEmpty()) { return offerWith(key, element, 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 offerWith(key, element, valueProcessor); } } } // Use the global processor if (localKeyRegistration != null && localKeyRegistration instanceof ElementHolder) { return offerWith(key, element, 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)) { if (valueContainer instanceof CompositeValueStore) { return ((CompositeValueStore) valueContainer).offer(key, element); } else if (valueContainer instanceof DataManipulator) { final ImmutableValue oldImmutableValue = ValueHelper.toImmutable((BaseValue) valueContainer.getValue((Key) key).get()); ((DataManipulator) valueContainer).set(key, element); final ImmutableValue immutableValue = ValueHelper.toImmutable((BaseValue) valueContainer.getValue((Key) key).get()); return DataTransactionResult.successReplaceResult(immutableValue, oldImmutableValue); } else { final ImmutableValue immutableValue = ValueHelper.toImmutable((BaseValue) valueContainer.getValue((Key) key).get()); return DataTransactionResult.failResult(immutableValue); } } } } return DataTransactionResult.failNoData(); } @SuppressWarnings("unchecked") default <E> DataTransactionResult offerWith(BaseValue<E> value, ValueProcessor<BaseValue<E>, E> processor) { return (DataTransactionResult) ((BiFunction) processor.getValueOfferHandler()).apply(this, value); } @SuppressWarnings("unchecked") @Override default <E> DataTransactionResult offer(BaseValue<E> value) { checkNotNull(value, "value"); final Key<? extends BaseValue<E>> key = value.getKey(); final E element = value.get(); // Check the local key registration final KeyRegistration<BaseValue<E>, E> localKeyRegistration = getKeyRegistration(key); if (localKeyRegistration == null) { if (requiresKeyRegistration()) { return DataTransactionResult.failNoData(); } } else { final List<ValueProcessor<BaseValue<E>, E>> processors = localKeyRegistration.getValueProcessors(); if (!processors.isEmpty()) { return offerWith(value, 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 offerWith(value, valueProcessor); } } } // Use the global processor if (localKeyRegistration != null && localKeyRegistration instanceof ElementHolder) { return offerWith(value, 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)) { final ImmutableValue oldImmutableValue = ValueHelper.toImmutable((BaseValue) valueContainer.getValue((Key) key).get()); if (valueContainer instanceof CompositeValueStore) { return ((CompositeValueStore) valueContainer).offer(key, element); } else if (valueContainer instanceof DataManipulator) { ((DataManipulator) valueContainer).set(key, element); final ImmutableValue immutableValue = ValueHelper.toImmutable(value); return DataTransactionResult.successReplaceResult(immutableValue, oldImmutableValue); } else { return DataTransactionResult.failResult(ValueHelper.toImmutable(value)); } } } } return DataTransactionResult.failNoData(); } @Override default DataTransactionResult offer(H valueContainer, MergeFunction function) { // TODO return DataTransactionResult.failNoData(); } @SuppressWarnings("unchecked") default DataTransactionResult removeWith(Key<?> key, ValueProcessor<?, ?> processor) { return (DataTransactionResult) ((BiFunction) processor.getRemoveHandler()).apply(key, this); } @SuppressWarnings("unchecked") @Override default DataTransactionResult remove(Key<?> key) { checkNotNull(key, "key"); // Check the local key registration final KeyRegistration<?, ?> localKeyRegistration = getKeyRegistration((Key) key); if (localKeyRegistration == null) { if (requiresKeyRegistration()) { return DataTransactionResult.failNoData(); } } else { final List<? extends ValueProcessor<? extends BaseValue<?>, ?>> processors = localKeyRegistration.getValueProcessors(); if (!processors.isEmpty()) { return removeWith(key, processors.get(0)); } } // 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 removeWith(key, valueProcessor); } } } // Use the global processor if (localKeyRegistration != null && localKeyRegistration instanceof ElementHolder) { return removeWith(key, ValueProcessor.getDefaultAttachedValueProcessor()); } // Custom data container doesn't support their data to be removed return DataTransactionResult.failNoData(); } @Override default DataTransactionResult undo(DataTransactionResult result) { if (result.getReplacedData().isEmpty() && result.getSuccessfulData().isEmpty()) { return DataTransactionResult.successNoData(); } final DataTransactionResult.Builder builder = DataTransactionResult.builder(); for (ImmutableValue<?> replaced : result.getReplacedData()) { builder.absorbResult(offer(replaced)); } for (ImmutableValue<?> successful : result.getSuccessfulData()) { builder.absorbResult(remove(successful)); } return builder.build(); } }