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}