001/*
002 * Configurate
003 * Copyright (C) zml and Configurate contributors
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.spongepowered.configurate.examples;
018
019import io.leangen.geantyref.TypeToken;
020import org.checkerframework.checker.nullness.qual.Nullable;
021import org.spongepowered.configurate.CommentedConfigurationNode;
022import org.spongepowered.configurate.ConfigurateException;
023import org.spongepowered.configurate.NodePath;
024import org.spongepowered.configurate.hocon.HoconConfigurationLoader;
025import org.spongepowered.configurate.objectmapping.ConfigSerializable;
026import org.spongepowered.configurate.reference.ConfigurationReference;
027import org.spongepowered.configurate.reference.ValueReference;
028import org.spongepowered.configurate.reference.WatchServiceListener;
029
030import java.io.IOException;
031import java.nio.file.Path;
032import java.nio.file.Paths;
033import java.util.List;
034import java.util.Objects;
035import java.util.UUID;
036
037public class ValueReferences {
038
039    private final WatchServiceListener listener;
040    private final ConfigurationReference<CommentedConfigurationNode> base;
041    private final ValueReference<String, CommentedConfigurationNode> name;
042    private final ValueReference<Integer, CommentedConfigurationNode> cookieCount;
043    private final ValueReference<List<TestObject>, CommentedConfigurationNode> complex;
044
045    @ConfigSerializable
046    static class TestObject {
047        String name;
048        UUID id = UUID.randomUUID();
049
050        @Override
051        public boolean equals(final Object o) {
052            if (this == o) {
053                return true;
054            }
055
056            if (!(o instanceof TestObject)) {
057                return false;
058            }
059
060            final TestObject that = (TestObject) o;
061            return this.name.equals(that.name)
062                    && this.id.equals(that.id);
063        }
064
065        @Override
066        public int hashCode() {
067            return Objects.hash(this.name, this.id);
068        }
069
070        @Override
071        public String toString() {
072            return "TestObject{"
073                    + "name='" + this.name + '\''
074                    + ", id=" + this.id
075                    + '}';
076        }
077    }
078
079    public ValueReferences(final Path configFile) throws IOException, ConfigurateException {
080        this.listener = WatchServiceListener.create();
081        this.base = this.listener.listenToConfiguration(file -> HoconConfigurationLoader.builder()
082                .defaultOptions(o -> o.shouldCopyDefaults(true)).path(file).build(), configFile);
083        this.base.updates().subscribe($ -> System.out.println("Configuration auto-reloaded"));
084        this.base.errors().subscribe(err -> {
085            final Throwable t = err.getValue();
086            System.out.println("Unable to " + err.getKey() + " the configuration: " + t.getMessage());
087            if (t.getCause() != null) {
088                System.out.println(t.getCause().getMessage());
089            }
090        });
091
092        this.name = this.base.referenceTo(String.class, "name");
093        this.name.subscribe(newName -> System.out.println("Reloaded, name is: " + newName));
094        this.cookieCount = this.base.referenceTo(Integer.class, NodePath.path("cookie-count"), 5);
095        this.complex = this.base.referenceTo(new TypeToken<List<TestObject>>() {}, "complex");
096        this.base.save();
097    }
098
099    public void repl() {
100        boolean running = true;
101        if (System.console() == null) {
102            System.err.println("Not at an interactive prompt");
103            this.printData();
104            return;
105        }
106
107        while (running) {
108            final @Nullable String next = System.console().readLine(">");
109            if (next == null) {
110                break;
111            }
112            final String[] cmd = next.split(" ", -1);
113            if (cmd.length == 0) {
114                continue;
115            }
116
117            switch (cmd[0]) {
118                case "stop":
119                    running = false;
120                    break;
121                case "name":
122                    if (cmd.length < 2) {
123                        System.err.println("Not enough arguments, usage: name <new-name>");
124                        break;
125                    }
126                    this.name.setAndSave(cmd[1]);
127                    System.out.println("Name: " + this.name.get());
128                    break;
129                case "dump":
130                    printData();
131                    break;
132                case "help":
133                    System.out.println("Value reference tester\n"
134                            + "Commands:\n\n"
135                            + "stop: Exit the loop\n"
136                            + "name <name>: Update the name in the config file\n"
137                            + "dump: Dump all accessed data in the config file\n"
138                            + "help: Show this message"
139                    );
140                    break;
141                default:
142                    System.err.println("Unknown command '" + next + "'");
143                    System.err.println("help for help");
144            }
145        }
146    }
147
148    public void printData() {
149        System.out.println("Name: " + this.name.get());
150        System.out.println("Cookie count: " + this.cookieCount.get());
151        System.out.println("Complex: ");
152        if (this.complex.get().isEmpty()) {
153            System.out.println("(empty)");
154        } else {
155            for (TestObject obj : this.complex.get()) {
156                System.out.println("- " + obj);
157            }
158        }
159    }
160
161    public void close() throws IOException {
162        this.base.close();
163        this.listener.close();
164    }
165
166    public static void main(final String[] args) {
167        if (args.length != 1) {
168            System.err.println("Usage: ./reference-example <file>");
169            return;
170        }
171        final Path path = Paths.get(args[0]);
172        try {
173            final ValueReferences engine = new ValueReferences(path);
174            engine.repl();
175            engine.close();
176        } catch (final IOException e) { // may be a ConfigurateException, or something else
177            System.out.println("Error loading configuration: " + e.getMessage());
178            e.printStackTrace();
179        }
180    }
181
182}