blob: 6a90b15251ac05afe84ea5d79eed8406a79c6ccb [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.ignite.internal.configuration.tree;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.apache.ignite.configuration.NamedListChange;
import org.apache.ignite.configuration.annotation.NamedConfigValue;
/**
* Configuration node implementation for the collection of named {@link InnerNode}s. Unlike implementations of
* {@link InnerNode}, this class is used for every named list in configuration.
*
* @param <N> Type of the {@link InnerNode} that is stored in named list node object.
*/
public final class NamedListNode<N extends InnerNode> implements NamedListChange<N>, TraversableTreeNode, ConstructableTreeNode {
/** Name of a synthetic configuration property that describes the order of elements in a named list. */
public static final String ORDER_IDX = "<idx>";
/** Configuration name for the synthetic key. */
private final String syntheticKeyName;
/** Supplier of new node objects when new list element node has to be created. */
private final Supplier<N> valSupplier;
/** Internal container for named list element. Maps keys to named list elements nodes. */
private final OrderedMap<N> map;
/**
* Default constructor.
*
* @param syntheticKeyName Name of the synthetic configuration value that will represent keys in a specially ordered
* representation syntax.
* @param valSupplier Closure to instantiate values.
*/
public NamedListNode(String syntheticKeyName, Supplier<N> valSupplier) {
this.syntheticKeyName = syntheticKeyName;
this.valSupplier = valSupplier;
map = new OrderedMap<>();
}
/**
* Copy constructor.
*
* @param node Other node.
*/
private NamedListNode(NamedListNode<N> node) {
syntheticKeyName = node.syntheticKeyName;
valSupplier = node.valSupplier;
map = new OrderedMap<>(node.map);
}
/** {@inheritDoc} */
@Override public <T> T accept(String key, ConfigurationVisitor<T> visitor) {
return visitor.visitNamedListNode(key, this);
}
/** {@inheritDoc} */
@Override public final List<String> namedListKeys() {
return Collections.unmodifiableList(map.keys());
}
/** {@inheritDoc} */
@Override public final N get(String key) {
return map.get(key);
}
/** {@inheritDoc} */
@Override public N get(int index) throws IndexOutOfBoundsException {
return map.get(index);
}
/** {@inheritDoc} */
@Override public int size() {
return map.size();
}
/** {@inheritDoc} */
@Override public NamedListChange<N> create(String key, Consumer<N> valConsumer) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valConsumer, "valConsumer");
checkNewKey(key);
N val = valSupplier.get();
map.put(key, val);
valConsumer.accept(val);
return this;
}
/** {@inheritDoc} */
@Override public NamedListChange<N> create(int index, String key, Consumer<N> valConsumer) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valConsumer, "valConsumer");
if (index < 0 || index > map.size())
throw new IndexOutOfBoundsException(index);
checkNewKey(key);
N val = valSupplier.get();
map.putByIndex(index, key, val);
valConsumer.accept(val);
return this;
}
/** {@inheritDoc} */
@Override public NamedListChange<N> createAfter(String precedingKey, String key, Consumer<N> valConsumer) {
Objects.requireNonNull(precedingKey, "precedingKey");
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valConsumer, "valConsumer");
if (!map.containsKey(precedingKey))
throw new IllegalArgumentException("Element with name " + precedingKey + " doesn't exist.");
checkNewKey(key);
N val = valSupplier.get();
map.putAfter(precedingKey, key, val);
valConsumer.accept(val);
return this;
}
/** {@inheritDoc} */
@Override public final NamedListChange<N> createOrUpdate(String key, Consumer<N> valConsumer) {
Objects.requireNonNull(key, "key");
Objects.requireNonNull(valConsumer, "valConsumer");
if (map.containsKey(key) && map.get(key) == null)
throw new IllegalArgumentException("You can't create entity that has just been deleted [key=" + key + ']');
N val = map.get(key);
if (val == null)
map.put(key, val = valSupplier.get());
else
map.put(key, val = (N)val.copy());
valConsumer.accept(val);
return this;
}
/**
* Checks that this new key can be inserted into the map.
* @param key New key.
* @throws IllegalArgumentException If key already exists.
*/
private void checkNewKey(String key) {
if (map.containsKey(key)) {
if (map.get(key) == null)
throw new IllegalArgumentException("You can't create entity that has just been deleted [key=" + key + ']');
throw new IllegalArgumentException("Element with name " + key + " already exists.");
}
}
/** {@inheritDoc} */
@Override public NamedListChange<N> delete(String key) {
Objects.requireNonNull(key, "key");
if (map.containsKey(key))
map.put(key, null);
return this;
}
/**
* @return Configuration name for the synthetic key.
*
* @see NamedConfigValue#syntheticKeyName()
*/
public String syntheticKeyName() {
return syntheticKeyName;
}
/**
* Deletes named list element.
*
* @param key Element's key.
*/
public void forceDelete(String key) {
map.remove(key);
}
/**
* Reorders keys in the map.
*
* @param orderedKeys List of keys in new order. Must have the same set of keys in it.
*/
public void reorderKeys(List<String> orderedKeys) {
map.reorderKeys(orderedKeys);
}
/** {@inheritDoc} */
@Override public void construct(String key, ConfigurationSource src) {
if (src == null)
map.put(key, null);
else {
N val = map.get(key);
val = val == null ? valSupplier.get() : (N)val.copy();
map.put(key, val);
src.descend(val);
}
}
/** {@inheritDoc} */
@Override public NamedListNode<N> copy() {
return new NamedListNode<>(this);
}
}