ibessonov commented on a change in pull request #41:
URL: https://github.com/apache/ignite-3/pull/41#discussion_r568481713



##########
File path: 
modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/configuration/ConfigurationStorageTest.java
##########
@@ -0,0 +1,208 @@
+package org.apache.ignite.configuration.sample.configuration;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.Configurator;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.sample.configuration.impl.ANode;
+import org.apache.ignite.configuration.storage.Data;
+import 
org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.apache.ignite.configuration.validation.ValidationIssue;
+import org.hamcrest.collection.IsMapContaining;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ConfigurationStorageTest {
+
+    private static final RootKey<?> KEY = () -> "key";
+    /** */
+    @Config
+    public static class AConfigurationSchema {
+        /** */
+        @ConfigValue
+        private BConfigurationSchema child;
+
+        /** */
+        @NamedConfigValue
+        private CConfigurationSchema elements;
+    }
+
+    /** */
+    @Config
+    public static class BConfigurationSchema {
+        /** */
+        @Value(immutable = true)
+        private int intCfg;
+
+        /** */
+        @Value
+        private String strCfg;
+    }
+
+    /** */
+    @Config
+    public static class CConfigurationSchema {
+        /** */
+        @Value
+        private String strCfg;
+    }
+
+    @Test
+    public void testPutGet() {
+        final TestConfigurationStorage storage = new 
TestConfigurationStorage();
+
+        final DynamicConfigurationController con = new 
DynamicConfigurationController();
+        final Configurator<?> configuration = con.getConfiguration();
+
+        ANode data = new ANode()
+            .initChild(init -> init.initIntCfg(1).initStrCfg("1"))
+            .initElements(change -> change.put("a", init -> 
init.initStrCfg("1")));
+
+        final ConfigurationChanger changer = new ConfigurationChanger(storage);
+        changer.init();
+
+        changer.registerConfiguration(KEY, configuration);
+
+        changer.change(Collections.singletonMap(KEY, data));
+
+        final Data dataFromStorage = storage.readAll();
+        final Map<String, Serializable> dataMap = dataFromStorage.values();
+
+        assertEquals(3, dataMap.size());
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.intCfg", 1));

Review comment:
       I think we should use static imports for matchers

##########
File path: 
modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/sample/configuration/ConfigurationStorageTest.java
##########
@@ -0,0 +1,208 @@
+package org.apache.ignite.configuration.sample.configuration;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.Map;
+import org.apache.ignite.configuration.ConfigurationChanger;
+import org.apache.ignite.configuration.Configurator;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.configuration.annotation.Config;
+import org.apache.ignite.configuration.annotation.ConfigValue;
+import org.apache.ignite.configuration.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.configuration.sample.configuration.impl.ANode;
+import org.apache.ignite.configuration.storage.Data;
+import 
org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.apache.ignite.configuration.validation.ValidationIssue;
+import org.hamcrest.collection.IsMapContaining;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class ConfigurationStorageTest {
+
+    private static final RootKey<?> KEY = () -> "key";
+    /** */
+    @Config
+    public static class AConfigurationSchema {
+        /** */
+        @ConfigValue
+        private BConfigurationSchema child;
+
+        /** */
+        @NamedConfigValue
+        private CConfigurationSchema elements;
+    }
+
+    /** */
+    @Config
+    public static class BConfigurationSchema {
+        /** */
+        @Value(immutable = true)
+        private int intCfg;
+
+        /** */
+        @Value
+        private String strCfg;
+    }
+
+    /** */
+    @Config
+    public static class CConfigurationSchema {
+        /** */
+        @Value
+        private String strCfg;
+    }
+
+    @Test
+    public void testPutGet() {
+        final TestConfigurationStorage storage = new 
TestConfigurationStorage();
+
+        final DynamicConfigurationController con = new 
DynamicConfigurationController();
+        final Configurator<?> configuration = con.getConfiguration();
+
+        ANode data = new ANode()
+            .initChild(init -> init.initIntCfg(1).initStrCfg("1"))
+            .initElements(change -> change.put("a", init -> 
init.initStrCfg("1")));
+
+        final ConfigurationChanger changer = new ConfigurationChanger(storage);
+        changer.init();
+
+        changer.registerConfiguration(KEY, configuration);
+
+        changer.change(Collections.singletonMap(KEY, data));
+
+        final Data dataFromStorage = storage.readAll();
+        final Map<String, Serializable> dataMap = dataFromStorage.values();
+
+        assertEquals(3, dataMap.size());
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.intCfg", 1));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.strCfg", "1"));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.elements.a.strCfg", 
"1"));
+    }
+
+    @Test
+    public void testModifiedFromAnotherStorage() {
+        final TestConfigurationStorage.Storage singleSource = new 
TestConfigurationStorage.Storage();
+
+        final TestConfigurationStorage storage1 = new 
TestConfigurationStorage(singleSource);
+        final TestConfigurationStorage storage2 = new 
TestConfigurationStorage(singleSource);
+
+        final DynamicConfigurationController con = new 
DynamicConfigurationController();
+        final Configurator<?> configuration = con.getConfiguration();
+
+        ANode data1 = new ANode()
+            .initChild(init -> init.initIntCfg(1).initStrCfg("1"))
+            .initElements(change -> change.put("a", init -> 
init.initStrCfg("1")));
+
+        ANode data2 = new ANode()
+            .initChild(init -> init.initIntCfg(2).initStrCfg("2"))
+            .initElements(change -> change
+                .put("a", init -> init.initStrCfg("2"))
+                .put("b", init -> init.initStrCfg("2"))
+            );
+
+        final ConfigurationChanger changer1 = new 
ConfigurationChanger(storage1);
+        changer1.init();
+
+        final ConfigurationChanger changer2 = new 
ConfigurationChanger(storage2);
+        changer2.init();
+
+        changer1.registerConfiguration(KEY, configuration);
+        changer2.registerConfiguration(KEY, configuration);
+
+        changer1.change(Collections.singletonMap(KEY, data1));
+        changer2.change(Collections.singletonMap(KEY, data2));
+
+        final Data dataFromStorage = storage1.readAll();
+        final Map<String, Serializable> dataMap = dataFromStorage.values();
+
+        assertEquals(4, dataMap.size());
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.intCfg", 2));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.strCfg", "2"));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.elements.a.strCfg", 
"2"));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.elements.b.strCfg", 
"2"));
+    }
+
+    @Test
+    public void testModifiedFromAnotherStorageWithIncompatibleChanges() {
+        final TestConfigurationStorage.Storage singleSource = new 
TestConfigurationStorage.Storage();
+
+        final TestConfigurationStorage storage1 = new 
TestConfigurationStorage(singleSource);
+        final TestConfigurationStorage storage2 = new 
TestConfigurationStorage(singleSource);
+
+        final DynamicConfigurationController con = new 
DynamicConfigurationController();
+
+        final Configurator<?> configuration = con.getConfiguration();
+
+        ANode data1 = new ANode()
+            .initChild(init -> init.initIntCfg(1).initStrCfg("1"))
+            .initElements(change -> change.put("a", init -> 
init.initStrCfg("1")));
+
+        ANode data2 = new ANode()
+            .initChild(init -> init.initIntCfg(2).initStrCfg("2"))
+            .initElements(change -> change
+                .put("a", init -> init.initStrCfg("2"))
+                .put("b", init -> init.initStrCfg("2"))
+            );
+
+        final ConfigurationChanger changer1 = new 
ConfigurationChanger(storage1);
+        changer1.init();
+
+        final ConfigurationChanger changer2 = new 
ConfigurationChanger(storage2);
+        changer2.init();
+
+        changer1.registerConfiguration(KEY, configuration);
+        changer2.registerConfiguration(KEY, configuration);
+
+        changer1.change(Collections.singletonMap(KEY, data1));
+
+        con.setHasIssues(true);
+
+        assertThrows(ConfigurationValidationException.class, () -> 
changer2.change(Collections.singletonMap(KEY, data2)));
+
+        final Data dataFromStorage = storage1.readAll();
+        final Map<String, Serializable> dataMap = dataFromStorage.values();
+
+        assertEquals(3, dataMap.size());
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.intCfg", 1));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.child.strCfg", "1"));
+        assertThat(dataMap, IsMapContaining.hasEntry("key.elements.a.strCfg", 
"1"));
+    }
+
+    private static class DynamicConfigurationController {
+
+        final Configurator<?> configuration;
+
+        private boolean hasIssues;
+
+        public DynamicConfigurationController() {
+            this(false);
+        }
+
+        public DynamicConfigurationController(boolean hasIssues) {
+            this.hasIssues = hasIssues;
+
+            configuration = Mockito.mock(Configurator.class);
+
+            
Mockito.when(configuration.validateChanges(Mockito.any())).then(mock -> {
+                if (this.hasIssues)
+                    return Collections.singletonList(new ValidationIssue());
+
+                return Collections.emptyList();
+            });
+        }
+
+        public void setHasIssues(boolean hasIssues) {
+            this.hasIssues = hasIssues;
+        }
+
+        public Configurator<?> getConfiguration() {
+            return configuration;
+        }
+    }
+
+}

Review comment:
       Please add empty line :)

##########
File path: 
modules/configuration-storage/src/main/java/org/apache/ignite/configuration/storage/ConfigurationStorage.java
##########
@@ -0,0 +1,43 @@
+/*
+ * 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.configuration.storage;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public interface ConfigurationStorage {

Review comment:
       Looks like this and the next class can be removed, right?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java
##########
@@ -0,0 +1,133 @@
+package org.apache.ignite.configuration;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.storage.ConfigurationStorage;
+import org.apache.ignite.configuration.storage.Data;
+import org.apache.ignite.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.configuration.tree.InnerNode;
+import org.apache.ignite.configuration.tree.NamedListNode;
+import org.apache.ignite.configuration.tree.TraversableTreeNode;
+import 
org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.apache.ignite.configuration.validation.ValidationIssue;
+
+// TODO: stupid stub name, think later
+public class ConfigurationChanger {
+
+    private Map<RootKey<?>, Configurator<?>> registry = new HashMap<>();
+
+    private ConfigurationStorage configurationStorage;
+
+    private final AtomicInteger version = new AtomicInteger(0);
+
+    public ConfigurationChanger(ConfigurationStorage configurationStorage) {
+        this.configurationStorage = configurationStorage;
+    }
+
+    public void init() {
+        final Data data = configurationStorage.readAll();
+        version.set(data.version());
+
+        configurationStorage.addListener(changedEntries -> {
+            // TODO: add tree update
+            version.set(changedEntries.version());
+        });
+
+        // TODO: iterate over data and fill Configurators
+    }
+
+    public void registerConfiguration(RootKey<?> key, Configurator<?> 
configurator) {
+        registry.put(key, configurator);
+    }
+
+    public <T extends ConfigurationTree<?, ?>> void change(Map<RootKey<?>, 
TraversableTreeNode> changes) {
+        Map<String, Serializable> allChanges = changes.entrySet().stream()
+            .map((Map.Entry<RootKey<?>, TraversableTreeNode> change) -> 
convertChangesToMap(change.getKey(), change.getValue()))
+            .flatMap(map -> map.entrySet().stream())
+            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+        boolean success = false;
+
+        List<ValidationIssue> validationIssues = Collections.emptyList();
+
+        while (!success) {
+            validationIssues = validate(changes);
+
+            final int version = this.version.get();
+
+            if (validationIssues.isEmpty())
+                success = configurationStorage.write(allChanges, version);
+            else
+                break;
+        }
+
+        if (!validationIssues.isEmpty())
+            throw new ConfigurationValidationException(validationIssues);
+    }
+
+    private List<ValidationIssue> validate(Map<RootKey<?>, 
TraversableTreeNode> changes) {
+        List<ValidationIssue> issues = new ArrayList<>();
+
+        for (Map.Entry<RootKey<?>, TraversableTreeNode> entry : 
changes.entrySet()) {
+            RootKey<?> rootKey = entry.getKey();
+            TraversableTreeNode changesForRoot = entry.getValue();
+
+            final Configurator<?> configurator = registry.get(rootKey);
+
+            List<ValidationIssue> list = 
configurator.validateChanges(changesForRoot);
+            issues.addAll(list);
+        }
+
+        return issues;
+    }
+
+    private Map<String, Serializable> convertChangesToMap(RootKey<?> rootKey, 
TraversableTreeNode node) {
+        Map<String, Serializable> values = new HashMap<>();
+
+        node.accept(null, new ConfigurationVisitor() {
+
+            String currentKey = rootKey.key();
+
+            @Override public void visitLeafNode(String key, Serializable val) {
+                values.put(currentKey + "." + key, val);
+            }
+
+            @Override public void visitInnerNode(String key, InnerNode node) {
+                String previousKey = currentKey;
+
+                if (key != null)
+                    currentKey += "." + key;

Review comment:
       Please use StringBuilder, concatenation in a recursive method is a bad 
idea.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java
##########
@@ -0,0 +1,133 @@
+package org.apache.ignite.configuration;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.storage.ConfigurationStorage;
+import org.apache.ignite.configuration.storage.Data;
+import org.apache.ignite.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.configuration.tree.InnerNode;
+import org.apache.ignite.configuration.tree.NamedListNode;
+import org.apache.ignite.configuration.tree.TraversableTreeNode;
+import 
org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.apache.ignite.configuration.validation.ValidationIssue;
+
+// TODO: stupid stub name, think later
+public class ConfigurationChanger {
+
+    private Map<RootKey<?>, Configurator<?>> registry = new HashMap<>();
+
+    private ConfigurationStorage configurationStorage;
+
+    private final AtomicInteger version = new AtomicInteger(0);
+
+    public ConfigurationChanger(ConfigurationStorage configurationStorage) {
+        this.configurationStorage = configurationStorage;
+    }
+
+    public void init() {
+        final Data data = configurationStorage.readAll();
+        version.set(data.version());
+
+        configurationStorage.addListener(changedEntries -> {
+            // TODO: add tree update
+            version.set(changedEntries.version());
+        });
+
+        // TODO: iterate over data and fill Configurators
+    }
+
+    public void registerConfiguration(RootKey<?> key, Configurator<?> 
configurator) {
+        registry.put(key, configurator);
+    }
+
+    public <T extends ConfigurationTree<?, ?>> void change(Map<RootKey<?>, 
TraversableTreeNode> changes) {
+        Map<String, Serializable> allChanges = changes.entrySet().stream()
+            .map((Map.Entry<RootKey<?>, TraversableTreeNode> change) -> 
convertChangesToMap(change.getKey(), change.getValue()))
+            .flatMap(map -> map.entrySet().stream())
+            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+        boolean success = false;
+
+        List<ValidationIssue> validationIssues = Collections.emptyList();
+
+        while (!success) {
+            validationIssues = validate(changes);
+
+            final int version = this.version.get();
+
+            if (validationIssues.isEmpty())
+                success = configurationStorage.write(allChanges, version);
+            else
+                break;
+        }
+
+        if (!validationIssues.isEmpty())
+            throw new ConfigurationValidationException(validationIssues);
+    }
+
+    private List<ValidationIssue> validate(Map<RootKey<?>, 
TraversableTreeNode> changes) {
+        List<ValidationIssue> issues = new ArrayList<>();
+
+        for (Map.Entry<RootKey<?>, TraversableTreeNode> entry : 
changes.entrySet()) {
+            RootKey<?> rootKey = entry.getKey();
+            TraversableTreeNode changesForRoot = entry.getValue();
+
+            final Configurator<?> configurator = registry.get(rootKey);
+
+            List<ValidationIssue> list = 
configurator.validateChanges(changesForRoot);
+            issues.addAll(list);
+        }
+
+        return issues;
+    }
+
+    private Map<String, Serializable> convertChangesToMap(RootKey<?> rootKey, 
TraversableTreeNode node) {
+        Map<String, Serializable> values = new HashMap<>();
+
+        node.accept(null, new ConfigurationVisitor() {
+
+            String currentKey = rootKey.key();
+
+            @Override public void visitLeafNode(String key, Serializable val) {
+                values.put(currentKey + "." + key, val);
+            }
+
+            @Override public void visitInnerNode(String key, InnerNode node) {
+                String previousKey = currentKey;
+
+                if (key != null)
+                    currentKey += "." + key;
+
+                node.traverseChildren(this);
+
+                currentKey = previousKey;
+            }
+
+            @Override public <N extends InnerNode> void 
visitNamedListNode(String key, NamedListNode<N> node) {
+                String previousKey = currentKey;
+
+                if (key != null)
+                    currentKey += "." + key;
+
+                for (String namedListKey : node.namedListKeys()) {
+                    String loopPreviousKey = currentKey;
+                    currentKey += "." + namedListKey;

Review comment:
       Keep in mind that keys in named lists must be escaped. Methods for that 
are locted in this PR right now: 
https://github.com/apache/ignite-3/pull/40/files

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/ConfigurationChanger.java
##########
@@ -0,0 +1,133 @@
+package org.apache.ignite.configuration;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.storage.ConfigurationStorage;
+import org.apache.ignite.configuration.storage.Data;
+import org.apache.ignite.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.configuration.tree.InnerNode;
+import org.apache.ignite.configuration.tree.NamedListNode;
+import org.apache.ignite.configuration.tree.TraversableTreeNode;
+import 
org.apache.ignite.configuration.validation.ConfigurationValidationException;
+import org.apache.ignite.configuration.validation.ValidationIssue;
+
+// TODO: stupid stub name, think later
+public class ConfigurationChanger {
+
+    private Map<RootKey<?>, Configurator<?>> registry = new HashMap<>();
+
+    private ConfigurationStorage configurationStorage;
+
+    private final AtomicInteger version = new AtomicInteger(0);
+
+    public ConfigurationChanger(ConfigurationStorage configurationStorage) {
+        this.configurationStorage = configurationStorage;
+    }
+
+    public void init() {
+        final Data data = configurationStorage.readAll();
+        version.set(data.version());
+
+        configurationStorage.addListener(changedEntries -> {
+            // TODO: add tree update
+            version.set(changedEntries.version());
+        });
+
+        // TODO: iterate over data and fill Configurators
+    }
+
+    public void registerConfiguration(RootKey<?> key, Configurator<?> 
configurator) {
+        registry.put(key, configurator);
+    }
+
+    public <T extends ConfigurationTree<?, ?>> void change(Map<RootKey<?>, 
TraversableTreeNode> changes) {
+        Map<String, Serializable> allChanges = changes.entrySet().stream()
+            .map((Map.Entry<RootKey<?>, TraversableTreeNode> change) -> 
convertChangesToMap(change.getKey(), change.getValue()))
+            .flatMap(map -> map.entrySet().stream())
+            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+
+        boolean success = false;
+
+        List<ValidationIssue> validationIssues = Collections.emptyList();
+
+        while (!success) {
+            validationIssues = validate(changes);
+
+            final int version = this.version.get();

Review comment:
       I don't see how this version is synchronized with the one that you 
validated on. We'll discuss it later.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/Configurator.java
##########
@@ -214,9 +205,13 @@ public T getRoot() {
         property.addListener(new PropertyListener<PROP, PROP>() {
             /** {@inheritDoc} */
             @Override public void update(PROP newValue, 
ConfigurationProperty<PROP, PROP> modifier) {
-                storage.save(key, newValue);
+//                storage.save(key, newValue);

Review comment:
       Yeah, about these listeners... I guess they'll be completely removed 
from the code, we'll discuss this later as well

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/storage/ConfigurationEntry.java
##########
@@ -0,0 +1,56 @@
+/*
+ * 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.configuration.storage;
+
+import java.io.Serializable;
+
+/**
+ * Key-value pair.
+ */
+public class ConfigurationEntry {

Review comment:
       I see two copies of the same class and it seems that none of them are 
actually used anywhere in code. Can you please remove both?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/validation/ValidationIssue.java
##########
@@ -0,0 +1,4 @@
+package org.apache.ignite.configuration.validation;

Review comment:
       File without a license...
   You can ask me how to set up automatic license header creation so you won't 
have to do it manually.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]


Reply via email to