001package conexp.fx.core.xml; 002 003/* 004 * #%L 005 * Concept Explorer FX 006 * %% 007 * Copyright (C) 2010 - 2023 Francesco Kriegel 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025import java.io.BufferedWriter; 026import java.io.File; 027import java.io.FileWriter; 028import java.io.IOException; 029import java.util.Map; 030 031import org.jsoup.Jsoup; 032import org.jsoup.nodes.Document; 033import org.jsoup.nodes.Element; 034 035import conexp.fx.core.collections.Collections3; 036 037/** 038 * Use an XMLFile for persistent configuration values. Each value is adressed by a structured key. Keys must be 039 * lower-case strings (!!!) and are simply structured by dots, like URLs or names within ontologies. 040 */ 041public final class XMLFile extends AbstractCompoundData { 042 043 private final File file; 044 045 public XMLFile(final File file) throws IOException { 046 super(Datatype.DOCUMENT, "", readElementFromFile(file), new Metadata(readElementFromFile(file))); 047 this.file = file; 048 } 049 050 public final File getFile() { 051 return file; 052 } 053 054 private synchronized static final Element readElementFromFile(final File file) throws IOException { 055 return Jsoup.parse(file, null).body(); 056 } 057 058 public synchronized final void store() throws IOException { 059 writeDocumentToFile(writeDataToDocument()); 060 } 061 062 private synchronized final Document writeDataToDocument() { 063 final Document document = new Document(""); 064 writeDataToElement(value, document, document.appendElement("metadata")); 065 return document; 066 } 067 068 private synchronized final void 069 writeDataToElement(final Map<String, Data<?>> map, final Element element, final Element metadata) { 070 for (final String key : Collections3.sort(map.keySet())) { 071 final Data<?> value = map.get(key); 072 Element metadata_data = null; 073 if (metadata != null) { 074 metadata_data = metadata.appendElement("data"); 075 metadata_data.appendElement("key").text(key); 076 metadata_data.appendElement("type").text(value.getType().toString()); 077 switch (value.getType()) { 078 case BOOLEAN_LIST: 079 case INTEGER_LIST: 080 case FLOAT_LIST: 081 case STRING_LIST: 082 case COMPOUND_LIST: 083 JsoupUtil.firstOrAppendElement(metadata_data, "metadata", "subkey").text(value.toListData().getSubkey()); 084 default: 085 } 086 } 087 final Element data = JsoupUtil.firstOrAppendElement(element, Key.toArray(key)); 088 switch (value.getType()) { 089 case BOOLEAN: 090 data.text(value.toBooleanData().getValue().toString()); 091 break; 092 case INTEGER: 093 data.text(value.toIntegerData().getValue().toString()); 094 break; 095 case FLOAT: 096 data.text(value.toFloatData().getValue().toString()); 097 break; 098 case STRING: 099 data.text(value.toStringData().getValue()); 100 break; 101 case COMPOUND: 102 writeDataToElement( 103 value.toCompoundData(), 104 data, 105 metadata != null ? JsoupUtil.firstOrAppendElement(metadata_data, "metadata") : null); 106 break; 107 case BOOLEAN_LIST: 108 for (Boolean boolean_ : value.toBooleanListData()) 109 data.appendElement(value.toListData().getSubkey()).text(boolean_.toString()); 110 break; 111 case INTEGER_LIST: 112 for (Integer integer : value.toIntegerListData()) 113 data.appendElement(value.toListData().getSubkey()).text(integer.toString()); 114 break; 115 case FLOAT_LIST: 116 for (Float floating : value.toFloatListData()) 117 data.appendElement(value.toListData().getSubkey()).text(floating.toString()); 118 break; 119 case STRING_LIST: 120 for (String string : value.toStringListData()) 121 data.appendElement(value.toListData().getSubkey()).text(string); 122 break; 123 case COMPOUND_LIST: 124 int i = 0; 125 for (Map<String, Data<?>> map_ : value.toCompoundListData()) 126 writeDataToElement( 127 map_, 128 data.appendElement(value.toListData().getSubkey()), 129 i++ == 0 && metadata != null ? JsoupUtil.firstOrAppendElement(metadata_data, "metadata") : null); 130 case METADATA: 131 default: 132 } 133 } 134 } 135 136 private synchronized final void writeDocumentToFile(final Document document) throws IOException { 137 final BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); 138 bufferedWriter.append(document.toString()); 139 bufferedWriter.close(); 140 } 141 142 public static final void createEmptyConfiguration(File file) throws IOException { 143// file.getParentFile().mkdirs(); 144 file.createNewFile(); 145 final BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file)); 146 bufferedWriter.append("<metadata>\r\n</metadata>"); 147 bufferedWriter.close(); 148 } 149}