001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.configuration.file; 020 021import com.plotsquared.core.configuration.Configuration; 022import com.plotsquared.core.configuration.InvalidConfigurationException; 023import com.plotsquared.core.configuration.MemoryConfiguration; 024 025import java.io.BufferedReader; 026import java.io.File; 027import java.io.FileInputStream; 028import java.io.FileNotFoundException; 029import java.io.FileOutputStream; 030import java.io.IOException; 031import java.io.InputStreamReader; 032import java.io.OutputStreamWriter; 033import java.io.Reader; 034import java.io.Writer; 035import java.nio.charset.StandardCharsets; 036import java.util.stream.Collectors; 037 038/** 039 * This is a base class for all File based implementations of {@link 040 * Configuration}. 041 */ 042public abstract class FileConfiguration extends MemoryConfiguration { 043 044 /** 045 * Creates an empty FileConfiguration with no default values. 046 */ 047 FileConfiguration() { 048 } 049 050 /** 051 * Creates an empty FileConfiguration using the specified {@link 052 * Configuration} as a source for all default values. 053 * 054 * @param defaults Default value provider 055 */ 056 public FileConfiguration(Configuration defaults) { 057 super(defaults); 058 } 059 060 /** 061 * Saves this FileConfiguration to the specified location. 062 * 063 * <p>If the file does not exist, it will be created. If already exists, it 064 * will be overwritten. If it cannot be overwritten or created, an 065 * exception will be thrown. 066 * 067 * <p>This method will save using the system default encoding, or possibly 068 * using UTF8. 069 * 070 * @param file File to save to. 071 * @throws IOException Thrown when the given file cannot be written to for 072 * any reason. 073 */ 074 public void save(File file) throws IOException { 075 File parent = file.getParentFile(); 076 if (parent != null) { 077 parent.mkdirs(); 078 } 079 080 String data = saveToString(); 081 082 try (Writer writer = new OutputStreamWriter( 083 new FileOutputStream(file), 084 StandardCharsets.UTF_8 085 )) { 086 writer.write(data); 087 } 088 } 089 090 /** 091 * Saves this FileConfiguration to a string, and returns it. 092 * 093 * @return String containing this configuration. 094 */ 095 public abstract String saveToString(); 096 097 /** 098 * Loads this FileConfiguration from the specified location. 099 * 100 * <p>All the values contained within this configuration will be removed, 101 * leaving only settings and defaults, and the new values will be loaded 102 * from the given file. 103 * 104 * <p>If the file cannot be loaded for any reason, an exception will be 105 * thrown. 106 * 107 * @param file File to load from. 108 * @throws FileNotFoundException Thrown when the given file cannot be 109 * opened. 110 * @throws IOException Thrown when the given file cannot be read. 111 * @throws InvalidConfigurationException Thrown when the given file is not 112 * a valid Configuration. 113 * @throws IllegalArgumentException Thrown when file is null. 114 */ 115 public void load(File file) throws IOException, InvalidConfigurationException { 116 117 try (FileInputStream stream = new FileInputStream(file)) { 118 load(new InputStreamReader(stream, StandardCharsets.UTF_8)); 119 } 120 } 121 122 /** 123 * Loads this FileConfiguration from the specified reader. 124 * 125 * <p>All the values contained within this configuration will be removed, 126 * leaving only settings and defaults, and the new values will be loaded 127 * from the given stream. 128 * 129 * @param reader the reader to load from 130 * @throws IOException thrown when underlying reader throws an IOException 131 * @throws InvalidConfigurationException thrown when the reader does not 132 * represent a valid Configuration 133 */ 134 public void load(Reader reader) throws IOException, InvalidConfigurationException { 135 136 String builder; 137 138 try (BufferedReader input = reader instanceof BufferedReader ? 139 (BufferedReader) reader : 140 new BufferedReader(reader)) { 141 142 builder = input.lines().map(line -> line + '\n').collect(Collectors.joining()); 143 } 144 145 loadFromString(builder); 146 } 147 148 /** 149 * Loads this FileConfiguration from the specified string, as 150 * opposed to from file. 151 * 152 * <p>All the values contained within this configuration will be removed, 153 * leaving only settings and defaults, and the new values will be loaded 154 * from the given string. 155 * 156 * <p>If the string is invalid in any way, an exception will be thrown. 157 * 158 * @param contents Contents of a Configuration to load. 159 * @throws InvalidConfigurationException Thrown if the specified string is 160 * invalid. 161 */ 162 public abstract void loadFromString(String contents) throws InvalidConfigurationException; 163 164 /** 165 * Compiles the header for this FileConfiguration and returns the 166 * result. 167 * 168 * <p>This will use the header from {@link #options()} -> {@link 169 * FileConfigurationOptions#header()}, respecting the rules of {@link 170 * FileConfigurationOptions#copyHeader()} if set. 171 * 172 * @return Compiled header 173 */ 174 protected abstract String buildHeader(); 175 176 @Override 177 public FileConfigurationOptions options() { 178 if (this.options == null) { 179 this.options = new FileConfigurationOptions(this); 180 } 181 182 return (FileConfigurationOptions) this.options; 183 } 184 185}