5353import org .spongepowered .configurate .gson .GsonConfigurationLoader ;
5454import org .spongepowered .configurate .loader .HeaderMode ;
5555
56+ import java .io .Closeable ;
5657import java .io .IOException ;
5758import java .lang .reflect .Type ;
5859import java .net .URL ;
6768 * This is the attempt to generalize as many actions as possible to have CLI and Plugins run on the same general setup-code.
6869 */
6970@ DebugDump
70- public class BlueMapService {
71+ public class BlueMapService implements Closeable {
7172 private final ServerInterface serverInterface ;
7273 private final BlueMapConfigProvider configs ;
7374
@@ -154,106 +155,112 @@ public synchronized void createOrUpdateWebApp(boolean force) throws Configuratio
154155 }
155156 }
156157
157- public synchronized Map <String , World > getWorlds () throws ConfigurationException , InterruptedException {
158+ public synchronized Map <String , World > getWorlds () throws InterruptedException {
158159 if (worlds == null ) loadWorldsAndMaps ();
159160 return worlds ;
160161 }
161162
162- public synchronized Map <String , BmMap > getMaps () throws ConfigurationException , InterruptedException {
163+ public synchronized Map <String , BmMap > getMaps () throws InterruptedException {
163164 if (maps == null ) loadWorldsAndMaps ();
164165 return maps ;
165166 }
166167
167- private synchronized void loadWorldsAndMaps () throws ConfigurationException , InterruptedException {
168+ private synchronized void loadWorldsAndMaps () throws InterruptedException {
168169 maps = new HashMap <>();
169170 worlds = new HashMap <>();
170171
171172 for (var entry : configs .getMapConfigs ().entrySet ()) {
172- MapConfig mapConfig = entry .getValue ();
173+ try {
174+ loadMapConfig (entry .getKey (), entry .getValue ());
175+ } catch (ConfigurationException ex ) {
176+ Logger .global .logError (ex );
177+ }
178+ }
179+
180+ worlds = Collections .unmodifiableMap (worlds );
181+ maps = Collections .unmodifiableMap (maps );
182+ }
173183
174- String id = entry . getKey ();
175- String name = mapConfig .getName ();
176- if (name == null ) name = id ;
184+ private synchronized void loadMapConfig ( String id , MapConfig mapConfig ) throws ConfigurationException , InterruptedException {
185+ String name = mapConfig .getName ();
186+ if (name == null ) name = id ;
177187
178- Path worldFolder = mapConfig .getWorld ();
188+ Path worldFolder = mapConfig .getWorld ();
179189
180- // if there is no world configured, we assume the map is static, or supplied from a different server
181- if (worldFolder == null ) {
182- Logger .global .logInfo ("The map '" + name + "' has no world configured. The map will be displayed, but not updated!" );
183- continue ;
184- }
190+ // if there is no world configured, we assume the map is static, or supplied from a different server
191+ if (worldFolder == null ) {
192+ Logger .global .logInfo ("The map '" + name + "' has no world configured. The map will be displayed, but not updated!" );
193+ return ;
194+ }
185195
186- if (!Files .isDirectory (worldFolder )) {
187- throw new ConfigurationException ("Failed to load map '" + id + "': \n " +
188- "'" + worldFolder .toAbsolutePath ().normalize () + "' does not exist or is no directory!\n " +
189- "Check if the 'world' setting in the config-file for that map is correct, or remove the entire config-file if you don't want that map." );
190- }
196+ if (!Files .isDirectory (worldFolder )) {
197+ throw new ConfigurationException (
198+ "'" + worldFolder .toAbsolutePath ().normalize () + "' does not exist or is no directory!\n " +
199+ "Check if the 'world' setting in the config-file for that map is correct, or remove the entire config-file if you don't want that map." );
200+ }
191201
192- String worldId ;
202+ String worldId ;
203+ try {
204+ worldId = getWorldId (worldFolder );
205+ } catch (IOException ex ) {
206+ throw new ConfigurationException (
207+ "Could not load the ID for the world (" + worldFolder .toAbsolutePath ().normalize () + ")!\n " +
208+ "Make sure BlueMap has read and write access/permissions to the world-files for this map." ,
209+ ex );
210+ }
211+
212+ World world = worlds .get (worldId );
213+ if (world == null ) {
193214 try {
194- worldId = getWorldId (worldFolder );
215+ world = new MCAWorld (worldFolder , mapConfig .getWorldSkyLight (), mapConfig .isIgnoreMissingLightData ());
216+ worlds .put (worldId , world );
195217 } catch (IOException ex ) {
196- throw new ConfigurationException ("Failed to load map '" + id + "': \n " +
197- "Could not load the ID for the world !\n " +
198- "Make sure BlueMap has read and write access/permissions to the world-files for this map. " ,
218+ throw new ConfigurationException (
219+ "Failed to load world '" + worldId + "' (" + worldFolder . toAbsolutePath (). normalize () + ") !\n " +
220+ "Is the level.dat of that world present and not corrupted? " ,
199221 ex );
200222 }
223+ }
201224
202- World world = worlds .get (worldId );
203- if (world == null ) {
204- try {
205- world = new MCAWorld (worldFolder , mapConfig .getWorldSkyLight (), mapConfig .isIgnoreMissingLightData ());
206- worlds .put (worldId , world );
207- } catch (IOException ex ) {
208- throw new ConfigurationException ("Failed to load world (" + worldId + ") for map '" + id + "'!\n " +
209- "Is the level.dat of that world present and not corrupted?" ,
210- ex );
211- }
212- }
213-
214- Storage storage = getStorage (mapConfig .getStorage ());
225+ Storage storage = getStorage (mapConfig .getStorage ());
215226
216- try {
217- BmMap map = new BmMap (
218- id ,
219- name ,
220- worldId ,
221- world ,
222- storage ,
223- getResourcePack (),
224- mapConfig
225- );
226- maps .put (id , map );
227-
228- // load marker-config by converting it first from hocon to json and then loading it with MarkerGson
229- ConfigurationNode markerSetNode = mapConfig .getMarkerSets ();
230- if (markerSetNode != null && !markerSetNode .empty ()) {
231- String markerJson = GsonConfigurationLoader .builder ()
232- .headerMode (HeaderMode .NONE )
233- .lenient (false )
234- .indent (0 )
235- .buildAndSaveString (markerSetNode );
236- Gson gson = MarkerGson .addAdapters (new GsonBuilder ())
237- .setFieldNamingPolicy (FieldNamingPolicy .LOWER_CASE_WITH_DASHES )
238- .create ();
239- Type markerSetType = new TypeToken <Map <String , MarkerSet >>() {}.getType ();
240- Map <String , MarkerSet > markerSets = gson .fromJson (markerJson , markerSetType );
241- map .getMarkerSets ().putAll (markerSets );
242- }
227+ try {
243228
244- } catch (ConfigurateException | JsonParseException ex ) {
245- throw new ConfigurationException ("Failed to load map '" + id + "': \n " +
246- "Failed to create the markers for this map!\n " +
247- "Make sure your marker-configuration for this map is valid." ,
248- ex );
249- } catch (IOException ex ) {
250- throw new ConfigurationException ("Failed to load map '" + id + "'!" , ex );
229+ BmMap map = new BmMap (
230+ id ,
231+ name ,
232+ worldId ,
233+ world ,
234+ storage ,
235+ getResourcePack (),
236+ mapConfig
237+ );
238+ maps .put (id , map );
239+
240+ // load marker-config by converting it first from hocon to json and then loading it with MarkerGson
241+ ConfigurationNode markerSetNode = mapConfig .getMarkerSets ();
242+ if (markerSetNode != null && !markerSetNode .empty ()) {
243+ String markerJson = GsonConfigurationLoader .builder ()
244+ .headerMode (HeaderMode .NONE )
245+ .lenient (false )
246+ .indent (0 )
247+ .buildAndSaveString (markerSetNode );
248+ Gson gson = MarkerGson .addAdapters (new GsonBuilder ())
249+ .setFieldNamingPolicy (FieldNamingPolicy .LOWER_CASE_WITH_DASHES )
250+ .create ();
251+ Type markerSetType = new TypeToken <Map <String , MarkerSet >>() {}.getType ();
252+ Map <String , MarkerSet > markerSets = gson .fromJson (markerJson , markerSetType );
253+ map .getMarkerSets ().putAll (markerSets );
251254 }
252255
256+ } catch (ConfigurateException | JsonParseException ex ) {
257+ throw new ConfigurationException (
258+ "Failed to create the markers for map '" + id + "'!\n " +
259+ "Make sure your marker-configuration for this map is valid." ,
260+ ex );
261+ } catch (IOException | ConfigurationException ex ) {
262+ throw new ConfigurationException ("Failed to load map '" + id + "'!" , ex );
253263 }
254-
255- worlds = Collections .unmodifiableMap (worlds );
256- maps = Collections .unmodifiableMap (maps );
257264 }
258265
259266 public synchronized Storage getStorage (String storageId ) throws ConfigurationException {
@@ -272,8 +279,20 @@ public synchronized Storage getStorage(String storageId) throws ConfigurationExc
272279 storage = storageConfig .createStorage ();
273280 storage .initialize ();
274281 } catch (Exception ex ) {
275- throw new ConfigurationException ("Failed to load and initialize the storage '" + storageId + "'!" ,
276- ex );
282+ ConfigurationException confEx = new ConfigurationException (
283+ "Failed to load and initialize the storage '" + storageId + "'!" ,
284+ ex
285+ );
286+
287+ if (storage != null ) {
288+ try {
289+ storage .close ();
290+ } catch (Exception closeEx ) {
291+ confEx .addSuppressed (closeEx );
292+ }
293+ }
294+
295+ throw confEx ;
277296 }
278297
279298 storages .put (storageId , storage );
@@ -404,4 +423,23 @@ public BlueMapConfigProvider getConfigs() {
404423 return configs ;
405424 }
406425
426+ @ Override
427+ public void close () throws IOException {
428+ IOException exception = null ;
429+
430+ for (Storage storage : storages .values ()) {
431+ try {
432+ if (storage != null ) {
433+ storage .close ();
434+ }
435+ } catch (IOException ex ) {
436+ if (exception == null ) exception = ex ;
437+ else exception .addSuppressed (ex );
438+ }
439+ }
440+
441+ if (exception != null )
442+ throw exception ;
443+ }
444+
407445}
0 commit comments