Ticket #7027: preferences-structures.patch
| File preferences-structures.patch, 38.2 KB (added by , 14 years ago) |
|---|
-
src/org/openstreetmap/josm/plugins/ReadRemotePluginInformationTask.java
148 148 StringBuilder sb = new StringBuilder(); 149 149 try { 150 150 /* replace %<x> with empty string or x=plugins (separated with comma) */ 151 String pl = Main.pref.getCollectionAsString("plugins");151 String pl = Utils.join(",", Main.pref.getCollection("plugins")); 152 152 String printsite = site.replaceAll("%<(.*)>", ""); 153 153 if(pl != null && pl.length() != 0) { 154 154 site = site.replaceAll("%<(.*)>", "$1"+pl); -
src/org/openstreetmap/josm/io/MirroredInputStream.java
14 14 import java.net.MalformedURLException; 15 15 import java.net.URL; 16 16 import java.net.URLConnection; 17 import java.util.ArrayList; 17 18 import java.util.Arrays; 18 19 import java.util.Collection; 19 20 import java.util.Enumeration; 21 import java.util.List; 20 22 import java.util.zip.ZipEntry; 21 23 import java.util.zip.ZipFile; 22 24 … … 187 189 String prefKey = getPrefKey(url, destDir); 188 190 long age = 0L; 189 191 File localFile = null; 190 Collection<String> localPathEntry = Main.pref.getCollection(prefKey); 191 if(localPathEntry.size() == 2) { 192 String[] lp = (String[]) localPathEntry.toArray(); 193 localFile = new File(lp[1]); 192 List<String> localPathEntry = new ArrayList<String>(Main.pref.getCollection(prefKey)); 193 if (localPathEntry.size() == 2) { 194 localFile = new File(localPathEntry.get(1)); 194 195 if(!localFile.exists()) 195 196 localFile = null; 196 197 else { … … 199 200 ) { 200 201 maxTime = Main.pref.getInteger("mirror.maxtime", 7*24*60*60); 201 202 } 202 age = System.currentTimeMillis() - Long.parseLong(l p[0]);203 age = System.currentTimeMillis() - Long.parseLong(localPathEntry.get(0)); 203 204 if (age < maxTime*1000) { 204 205 return localFile; 205 206 } -
src/org/openstreetmap/josm/data/Preferences.java
21 21 import java.util.Arrays; 22 22 import java.util.Collection; 23 23 import java.util.Collections; 24 import java.util.Iterator; 25 import java.util.LinkedHashMap; 24 26 import java.util.LinkedList; 25 27 import java.util.List; 26 28 import java.util.Map; … … 34 36 35 37 import javax.swing.JOptionPane; 36 38 import javax.swing.UIManager; 39 import javax.xml.stream.XMLInputFactory; 40 import javax.xml.stream.XMLStreamConstants; 41 import javax.xml.stream.XMLStreamException; 42 import javax.xml.stream.XMLStreamReader; 43 import javax.xml.parsers.SAXParserFactory; 44 import javax.xml.transform.stream.StreamSource; 45 import javax.xml.validation.Schema; 46 import javax.xml.validation.Validator; 47 import javax.xml.validation.SchemaFactory; 48 import javax.xml.transform.stax.StAXSource; 37 49 38 50 import org.openstreetmap.josm.Main; 51 import org.openstreetmap.josm.io.MirroredInputStream; 39 52 import org.openstreetmap.josm.io.XmlWriter; 40 53 import org.openstreetmap.josm.tools.ColorHelper; 41 54 import org.openstreetmap.josm.tools.Utils; 42 55 import org.openstreetmap.josm.tools.XmlObjectParser; 43 import org.xml.sax.SAXException;44 56 45 57 /** 46 58 * This class holds all preferences for JOSM. … … 74 86 protected final SortedMap<String, String> defaults = new TreeMap<String, String>(); 75 87 protected final SortedMap<String, String> colornames = new TreeMap<String, String>(); 76 88 77 public interface PreferenceChangeEvent{ 89 protected final SortedMap<String, Collection<String>> collectionProperties = new TreeMap<String, Collection<String>>(); 90 protected final SortedMap<String, Collection<String>> collectionDefaults = new TreeMap<String, Collection<String>>(); 91 92 protected final SortedMap<String, Collection<Collection<String>>> arrayProperties = new TreeMap<String, Collection<Collection<String>>>(); 93 protected final SortedMap<String, Collection<Collection<String>>> arrayDefaults = new TreeMap<String, Collection<Collection<String>>>(); 94 95 protected final SortedMap<String, Collection<Map<String,String>>> listOfStructsProperties = new TreeMap<String, Collection<Map<String,String>>>(); 96 protected final SortedMap<String, Collection<Map<String,String>>> listOfStructsDefaults = new TreeMap<String, Collection<Map<String,String>>>(); 97 98 public interface PreferenceChangeEvent { 78 99 String getKey(); 79 100 String getOldValue(); 80 101 String getNewValue(); … … 445 466 446 467 private void load(boolean old) throws Exception { 447 468 properties.clear(); 448 if (!Main.applet) {449 final BufferedReader in = new BufferedReader(new InputStreamReader(450 new FileInputStream(old ? getOldPreferenceFile() : getPreferenceFile()), "utf-8"));469 if (!Main.applet) { 470 File pref = old ? getOldPreferenceFile() : getPreferenceFile(); 471 BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(pref), "utf-8")); 451 472 /* FIXME: TODO: remove old style config file end of 2012 */ 452 473 try { 453 474 if (old) { … … 455 476 int v = in.read(); 456 477 in.reset(); 457 478 if(v == '<') { 479 validateXML(in); 480 Utils.close(in); 481 in = new BufferedReader(new InputStreamReader(new FileInputStream(pref), "utf-8")); 458 482 fromXML(in); 459 483 } else { 460 484 int lineNumber = 0; … … 475 499 throw new IOException(tr("Malformed config file at lines {0}", errLines)); 476 500 } 477 501 } else { 502 validateXML(in); 503 Utils.close(in); 504 in = new BufferedReader(new InputStreamReader(new FileInputStream(pref), "utf-8")); 478 505 fromXML(in); 479 506 } 480 507 } finally { … … 731 758 return 0.0; 732 759 } 733 760 761 @Deprecated 734 762 synchronized public String getCollectionAsString(final String key) { 735 763 String s = get(key); 736 764 if(s != null && s.length() != 0) { … … 739 767 return s; 740 768 } 741 769 770 @Deprecated 742 771 public boolean isCollection(String key, boolean def) { 743 772 String s = get(key); 744 773 if (s != null && s.length() != 0) … … 754 783 * @return the corresponding value if the property has been set before, 755 784 * def otherwise 756 785 */ 757 synchronizedpublic Collection<String> getCollection(String key, Collection<String> def) {786 public Collection<String> getCollection(String key, Collection<String> def) { 758 787 putCollectionDefault(key, def); 759 String s = get(key); 760 if(s != null && s.length() != 0) 761 return Arrays.asList(s.split("\u001e", -1)); 762 return def; 788 Collection<String> prop = getCollectionInternal(key); 789 if (prop != null) 790 return prop; 791 else 792 return def; 763 793 } 764 794 765 795 /** … … 768 798 * @return the corresponding value if the property has been set before, 769 799 * an empty Collection otherwise. 770 800 */ 771 synchronizedpublic Collection<String> getCollection(String key) {801 public Collection<String> getCollection(String key) { 772 802 putCollectionDefault(key, null); 773 String s = get(key); 774 if (s != null && s.length() != 0) 775 return Arrays.asList(s.split("\u001e", -1)); 776 return Collections.emptyList(); 803 Collection<String> prop = getCollectionInternal(key); 804 if (prop != null) 805 return prop; 806 else 807 return Collections.emptyList(); 777 808 } 778 809 810 synchronized private Collection<String> getCollectionInternal(String key) { 811 Collection<String> prop = collectionProperties.get(key); 812 if (prop != null) 813 return prop; 814 else { 815 String s = properties.get(key); 816 if(s != null) { 817 prop = Arrays.asList(s.split("\u001e", -1)); 818 collectionProperties.put(key, prop); 819 properties.remove(key); 820 return prop; 821 } 822 } 823 return null; 824 } 825 779 826 /* old style conversion, replace by above call after some transition time */ 780 827 /* remove this function, when no more old-style preference collections in the code */ 781 828 @Deprecated … … 798 845 putCollection(key, a); 799 846 } 800 847 801 synchronized public boolean putCollection(String key, Collection<String> val) { 802 return put(key, Utils.join("\u001e", val)); 848 public boolean putCollection(String key, Collection<String> value) { 849 Collection<String> oldValue = null; 850 synchronized (this) { 851 if (value == null) { 852 boolean changed = collectionProperties.remove(key) != null; 853 changed |= properties.remove(key) != null; 854 if (!changed) return false; 855 } else { 856 oldValue = getCollectionInternal(key); 857 if (equalCollection(value, oldValue)) return false; 858 Collection<String> defValue = collectionDefaults.get(key); 859 if (oldValue == null && equalCollection(value, defValue)) return false; 860 861 Collection<String> valueCopy = new ArrayList<String>(value); 862 collectionProperties.put(key, valueCopy); 863 try { 864 save(); 865 } catch(IOException e){ 866 System.out.println(tr("Warning: failed to persist preferences to ''{0}''", getPreferenceFile().getAbsoluteFile())); 867 } 868 } 869 } 870 // Call outside of synchronized section in case some listener wait for other thread that wait for preference lock 871 // firePreferenceChanged(key, oldValue, value); 872 return true; 803 873 } 804 874 875 private static boolean equalCollection(Collection<String> a, Collection<String> b) { 876 if (a == null) return b == null; 877 if (b == null) return false; 878 if (a.size() != b.size()) return false; 879 Iterator<String> itA = a.iterator(); 880 Iterator<String> itB = b.iterator(); 881 while (itA.hasNext()) { 882 String aStr = itA.next(); 883 String bStr = itB.next(); 884 if (!Utils.equal(aStr,bStr)) return false; 885 } 886 return true; 887 } 888 805 889 /** 806 890 * Saves at most {@code maxsize} items of collection {@code val}. 807 891 */ … … 817 901 } 818 902 819 903 synchronized private void putCollectionDefault(String key, Collection<String> val) { 820 putDefault(key, Utils.join("\u001e", val));904 collectionDefaults.put(key, val); 821 905 } 822 906 823 907 /** 824 908 * Used to read a 2-dimensional array of strings from the preference file. 825 909 * If not a single entry could be found, def is returned. 826 910 */ 827 synchronized public Collection<Collection<String>> getArray(String key, 828 Collection<Collection<String>> def) 829 { 830 if(def != null) { 911 synchronized public Collection<Collection<String>> getArray(String key, Collection<Collection<String>> def) { 912 if (def != null) { 831 913 putArrayDefault(key, def); 832 914 } 833 key += "."; 834 int num = 0; 835 Collection<Collection<String>> col = new LinkedList<Collection<String>>(); 836 while(properties.containsKey(key+num)) { 837 col.add(getCollection(key+num++, null)); 838 } 839 return num == 0 ? def : col; 840 } 915 Collection<Collection<String>> prop = getArrayInternal(key); 916 if (prop != null) 917 return prop; 918 else 919 return def; 920 } 841 921 842 synchronized public boolean putArray(String key, Collection<Collection<String>> val) { 843 boolean changed = false; 844 key += "."; 845 Collection<String> keys = getAllPrefix(key).keySet(); 846 if(val != null) { 922 synchronized private Collection<Collection<String>> getArrayInternal(String key) { 923 Collection<Collection<String>> prop = arrayProperties.get(key); 924 if (prop != null) 925 return prop; 926 else { 927 String keyDot = key + "."; 847 928 int num = 0; 848 for(Collection<String> c : val) { 849 keys.remove(key+num); 850 changed |= putCollection(key+num++, c); 929 Collection<Collection<String>> col = new ArrayList<Collection<String>>(); 930 while (true) { 931 Collection<String> c = getCollectionInternal(keyDot+num); 932 if (c == null) { 933 break; 934 } 935 col.add(c); 936 collectionProperties.remove(keyDot+num); 937 num++; 851 938 } 939 if (num > 0) { 940 arrayProperties.put(key, col); 941 return col; 942 } 852 943 } 853 int l = key.length(); 854 for(String k : keys) { 855 try { 856 Integer.valueOf(k.substring(l)); 857 changed |= put(k, null); 858 } catch(NumberFormatException e) { 859 /* everything which does not end with a number should not be deleted */ 944 return null; 945 } 946 947 public boolean putArray(String key, Collection<Collection<String>> value) { 948 boolean changed = false; 949 950 Collection<Collection<String>> oldValue; 951 952 synchronized (this) { 953 if (value == null) { 954 getArrayInternal(key); 955 if (arrayProperties.remove(key) != null) return false; 956 } else { 957 oldValue = getArrayInternal(key); 958 if (equalArray(oldValue, value)) return false; 959 960 Collection<Collection<String>> defValue = arrayDefaults.get(key); 961 if (oldValue == null && equalArray(value, defValue)) return false; 962 963 Collection<Collection<String>> valueCopy = new ArrayList<Collection<String>>(value.size()); 964 for (Collection<String> lst : value) { 965 valueCopy.add(new ArrayList<String>(lst)); 966 } 967 arrayProperties.put(key, valueCopy); 968 try { 969 save(); 970 } catch(IOException e){ 971 System.out.println(tr("Warning: failed to persist preferences to ''{0}''", getPreferenceFile().getAbsoluteFile())); 972 } 860 973 } 861 974 } 862 return changed; 975 // Call outside of synchronized section in case some listener wait for other thread that wait for preference lock 976 // firePreferenceChanged(key, oldValue, value); 977 return true; 863 978 } 864 979 980 private static boolean equalArray(Collection<Collection<String>> a, Collection<Collection<String>> b) { 981 if (a == null) return b == null; 982 if (b == null) return false; 983 if (a.size() != b.size()) return false; 984 Iterator<Collection<String>> itA = a.iterator(); 985 Iterator<Collection<String>> itB = b.iterator(); 986 while (itA.hasNext()) { 987 if (!equalCollection(itA.next(), itB.next())) return false; 988 } 989 return true; 990 } 991 865 992 synchronized private void putArrayDefault(String key, Collection<Collection<String>> val) { 866 key += ".";867 Collection<String> keys = getAllPrefixDefault(key).keySet();868 int num = 0; 869 for(Collection<String> c : val) {870 keys.remove(key+num);871 put CollectionDefault(key+num++, c);993 arrayDefaults.put(key, val); 994 } 995 996 public Collection<Map<String, String>> getListOfStructs(String key, Collection<Map<String, String>> def) { 997 if (def != null) { 998 putListOfStructsDefault(key, def); 872 999 } 873 int l = key.length(); 874 for(String k : keys) { 875 try { 876 Integer.valueOf(k.substring(l)); 877 defaults.remove(k); 878 } catch(Exception e) { 879 /* everything which does not end with a number should not be deleted */ 1000 Collection<Map<String, String>> prop = getListOfStructsInternal(key); 1001 if (prop != null) 1002 return prop; 1003 else 1004 return def; 1005 } 1006 1007 public Collection<Map<String, String>> getListOfStructsInternal(String key) { 1008 Collection<Map<String, String>> prop = listOfStructsProperties.get(key); 1009 if (prop != null) 1010 return prop; 1011 else { 1012 Collection<Collection<String>> array = getArrayInternal(key); 1013 if (array == null) return null; 1014 prop = new ArrayList<Map<String, String>>(array.size()); 1015 for (Collection<String> mapStr : array) { 1016 Map<String, String> map = new LinkedHashMap<String, String>(); 1017 for (String key_value : mapStr) { 1018 final int i = key_value.indexOf(':'); 1019 if (i == -1 || i == 0) { 1020 continue; 1021 } 1022 String k = key_value.substring(0,i); 1023 String v = key_value.substring(i+1); 1024 map.put(k, v); 1025 } 1026 prop.add(map); 880 1027 } 1028 arrayProperties.remove(key); 1029 listOfStructsProperties.put(key,prop); 1030 return prop; 881 1031 } 882 1032 } 883 1033 1034 public boolean putListOfStructs(String key, Collection<Map<String, String>> value) { 1035 boolean changed = false; 1036 1037 Collection<Map<String, String>> oldValue; 1038 1039 synchronized (this) { 1040 if (value == null) { 1041 getListOfStructsInternal(key); 1042 if (listOfStructsProperties.remove(key) != null) return false; 1043 } else { 1044 oldValue = getListOfStructsInternal(key); 1045 if (equalListOfStructs(oldValue, value)) return false; 1046 1047 Collection<Map<String, String>> defValue = listOfStructsDefaults.get(key); 1048 if (oldValue == null && equalListOfStructs(value, defValue)) return false; 1049 1050 Collection<Map<String, String>> valueCopy = new ArrayList<Map<String, String>>(value.size()); 1051 for (Map<String, String> map : value) { 1052 valueCopy.add(new LinkedHashMap<String,String>(map)); 1053 } 1054 listOfStructsProperties.put(key, valueCopy); 1055 try { 1056 save(); 1057 } catch(IOException e){ 1058 System.out.println(tr("Warning: failed to persist preferences to ''{0}''", getPreferenceFile().getAbsoluteFile())); 1059 } 1060 } 1061 } 1062 // Call outside of synchronized section in case some listener wait for other thread that wait for preference lock 1063 // firePreferenceChanged(key, oldValue, value); 1064 return true; 1065 } 1066 1067 private static boolean equalListOfStructs(Collection<Map<String, String>> a, Collection<Map<String, String>> b) { 1068 if (a == null) return b == null; 1069 if (b == null) return false; 1070 if (a.size() != b.size()) return false; 1071 Iterator<Map<String, String>> itA = a.iterator(); 1072 Iterator<Map<String, String>> itB = b.iterator(); 1073 while (itA.hasNext()) { 1074 if (!equalMap(itA.next(), itB.next())) return false; 1075 } 1076 return true; 1077 } 1078 1079 private static boolean equalMap(Map<String, String> a, Map<String, String> b) { 1080 if (a == null) return b == null; 1081 if (b == null) return false; 1082 if (a.size() != b.size()) return false; 1083 for (Entry<String, String> e : a.entrySet()) { 1084 if (!Utils.equal(e.getValue(), b.get(e.getKey()))) return false; 1085 } 1086 return true; 1087 } 1088 1089 synchronized private void putListOfStructsDefault(String key, Collection<Map<String, String>> val) { 1090 listOfStructsDefaults.put(key, val); 1091 } 1092 884 1093 @Retention(RetentionPolicy.RUNTIME) public @interface pref { } 885 1094 @Retention(RetentionPolicy.RUNTIME) public @interface writeExplicitly { } 886 1095 … … 910 1119 * same as above, but returns def if nothing was found 911 1120 */ 912 1121 public <T> List<T> getListOfStructs(String key, Collection<T> def, Class<T> klass) { 913 Collection< Collection<String>> array=914 get Array(key, def == null ? null : serializeListOfStructs(def, klass));915 if ( array== null)1122 Collection<Map<String,String>> prop = 1123 getListOfStructs(key, def == null ? null : serializeListOfStructs(def, klass)); 1124 if (prop == null) 916 1125 return def == null ? null : new ArrayList<T>(def); 917 1126 List<T> lst = new ArrayList<T>(); 918 for ( Collection<String> entries : array) {1127 for (Map<String,String> entries : prop) { 919 1128 T struct = deserializeStruct(entries, klass); 920 1129 lst.add(struct); 921 1130 } … … 936 1145 * @return true if something has changed 937 1146 */ 938 1147 public <T> boolean putListOfStructs(String key, Collection<T> val, Class<T> klass) { 939 return put Array(key, serializeListOfStructs(val, klass));1148 return putListOfStructs(key, serializeListOfStructs(val, klass)); 940 1149 } 941 1150 942 private <T> Collection< Collection<String>> serializeListOfStructs(Collection<T> l, Class<T> klass) {1151 private <T> Collection<Map<String,String>> serializeListOfStructs(Collection<T> l, Class<T> klass) { 943 1152 if (l == null) 944 1153 return null; 945 Collection< Collection<String>> vals = new ArrayList<Collection<String>>();1154 Collection<Map<String,String>> vals = new ArrayList<Map<String,String>>(); 946 1155 for (T struct : l) { 947 1156 if (struct == null) { 948 1157 continue; … … 952 1161 return vals; 953 1162 } 954 1163 955 private <T> Collection<String> serializeStruct(T struct, Class<T> klass) {1164 private <T> Map<String,String> serializeStruct(T struct, Class<T> klass) { 956 1165 T structPrototype; 957 1166 try { 958 1167 structPrototype = klass.newInstance(); … … 962 1171 throw new RuntimeException(ex); 963 1172 } 964 1173 965 Collection<String> hash = new ArrayList<String>();1174 Map<String,String> hash = new LinkedHashMap<String,String>(); 966 1175 for (Field f : klass.getDeclaredFields()) { 967 1176 if (f.getAnnotation(pref.class) == null) { 968 1177 continue; … … 973 1182 Object defaultFieldValue = f.get(structPrototype); 974 1183 if (fieldValue != null) { 975 1184 if (f.getAnnotation(writeExplicitly.class) != null || !Utils.equal(fieldValue, defaultFieldValue)) { 976 hash. add(String.format("%s:%s", f.getName().replace("_", "-"), fieldValue.toString()));1185 hash.put(f.getName().replace("_", "-"), fieldValue.toString()); 977 1186 } 978 1187 } 979 1188 } catch (IllegalArgumentException ex) { … … 985 1194 return hash; 986 1195 } 987 1196 988 private <T> T deserializeStruct( Collection<String> hash, Class<T> klass) {1197 private <T> T deserializeStruct(Map<String,String> hash, Class<T> klass) { 989 1198 T struct = null; 990 1199 try { 991 1200 struct = klass.newInstance(); … … 994 1203 } catch (IllegalAccessException ex) { 995 1204 throw new RuntimeException(); 996 1205 } 997 for (String key_value : hash) { 998 final int i = key_value.indexOf(':'); 999 if (i == -1 || i == 0) { 1000 continue; 1001 } 1002 String key = key_value.substring(0,i); 1003 String valueString = key_value.substring(i+1); 1004 1206 for (Entry<String,String> key_value : hash.entrySet()) { 1005 1207 Object value = null; 1006 1208 Field f; 1007 1209 try { 1008 f = klass.getDeclaredField(key .replace("-", "_"));1210 f = klass.getDeclaredField(key_value.getKey().replace("-", "_")); 1009 1211 } catch (NoSuchFieldException ex) { 1010 1212 continue; 1011 1213 } catch (SecurityException ex) { … … 1016 1218 } 1017 1219 f.setAccessible(true); 1018 1220 if (f.getType() == Boolean.class || f.getType() == boolean.class) { 1019 value = Boolean.parseBoolean( valueString);1221 value = Boolean.parseBoolean(key_value.getValue()); 1020 1222 } else if (f.getType() == Integer.class || f.getType() == int.class) { 1021 1223 try { 1022 value = Integer.parseInt( valueString);1224 value = Integer.parseInt(key_value.getValue()); 1023 1225 } catch (NumberFormatException nfe) { 1024 1226 continue; 1025 1227 } 1026 1228 } else if (f.getType() == Double.class || f.getType() == double.class) { 1027 1229 try { 1028 value = Double.parseDouble( valueString);1230 value = Double.parseDouble(key_value.getValue()); 1029 1231 } catch (NumberFormatException nfe) { 1030 1232 continue; 1031 1233 } 1032 1234 } else if (f.getType() == String.class) { 1033 value = valueString;1235 value = key_value.getValue(); 1034 1236 } else 1035 1237 throw new RuntimeException("unsupported preference primitive type"); 1036 1238 … … 1079 1281 putCollection("pluginmanager.sites", sites); 1080 1282 } 1081 1283 1082 public static class XMLTag { 1083 public String key; 1084 public String value; 1284 protected XMLStreamReader parser; 1285 1286 public void validateXML(Reader in) throws Exception { 1287 SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema"); 1288 Schema schema = factory.newSchema(new StreamSource(new MirroredInputStream("resource://data/preferences.xsd"))); 1289 XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(in); 1290 Validator validator = schema.newValidator(); 1291 validator.validate(new StAXSource(parser)); 1085 1292 } 1086 public static class XMLCollection { 1087 public String key; 1293 1294 public void fromXML(Reader in) throws XMLStreamException { 1295 XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(in); 1296 this.parser = parser; 1297 parse(); 1088 1298 } 1089 public static class XMLEntry { 1090 public String value; 1299 1300 public void parse() throws XMLStreamException { 1301 int event = parser.getEventType(); 1302 while (true) { 1303 if (event == XMLStreamConstants.START_ELEMENT) { 1304 parseRoot(); 1305 } else if (event == XMLStreamConstants.END_ELEMENT) { 1306 return; 1307 } 1308 if (parser.hasNext()) { 1309 event = parser.next(); 1310 } else { 1311 break; 1312 } 1313 } 1314 parser.close(); 1091 1315 } 1092 public void fromXML(Reader in) throws SAXException { 1093 XmlObjectParser parser = new XmlObjectParser(); 1094 parser.map("tag", XMLTag.class); 1095 parser.map("entry", XMLEntry.class); 1096 parser.map("collection", XMLCollection.class); 1097 parser.startWithValidation(in, 1098 "http://josm.openstreetmap.de/preferences-1.0", "resource://data/preferences.xsd"); 1099 LinkedList<String> vals = new LinkedList<String>(); 1100 while(parser.hasNext()) { 1101 Object o = parser.next(); 1102 if(o instanceof XMLTag) { 1103 properties.put(((XMLTag)o).key, ((XMLTag)o).value); 1104 } else if (o instanceof XMLEntry) { 1105 vals.add(((XMLEntry)o).value); 1106 } else if (o instanceof XMLCollection) { 1107 properties.put(((XMLCollection)o).key, Utils.join("\u001e", vals)); 1108 vals = new LinkedList<String>(); 1316 1317 public void parseRoot() throws XMLStreamException { 1318 while (true) { 1319 int event = parser.next(); 1320 if (event == XMLStreamConstants.START_ELEMENT) { 1321 if (parser.getLocalName().equals("tag")) { 1322 properties.put(parser.getAttributeValue(null, "key"), parser.getAttributeValue(null, "value")); 1323 jumpToEnd(); 1324 } else if (parser.getLocalName().equals("list") || parser.getLocalName().equals("collection")) { 1325 parseToplevelList(); 1326 } else { 1327 throwException("Unexpected element: "+parser.getLocalName()); 1328 } 1329 } else if (event == XMLStreamConstants.END_ELEMENT) { 1330 return; 1109 1331 } 1110 1332 } 1111 1333 } 1112 1334 1335 private void jumpToEnd() throws XMLStreamException { 1336 while (true) { 1337 int event = parser.next(); 1338 if (event == XMLStreamConstants.START_ELEMENT) { 1339 jumpToEnd(); 1340 } else if (event == XMLStreamConstants.END_ELEMENT) { 1341 return; 1342 } 1343 } 1344 } 1345 1346 protected void parseToplevelList() throws XMLStreamException { 1347 String key = parser.getAttributeValue(null, "key"); 1348 Collection<String> entries = null; 1349 Collection<Collection<String>> lists = null; 1350 Collection<Map<String, String>> maps = null; 1351 while (true) { 1352 int event = parser.next(); 1353 if (event == XMLStreamConstants.START_ELEMENT) { 1354 if (parser.getLocalName().equals("entry")) { 1355 if (entries == null) { 1356 entries = new ArrayList<String>(); 1357 } 1358 entries.add(parser.getAttributeValue(null, "value")); 1359 jumpToEnd(); 1360 } else if (parser.getLocalName().equals("list")) { 1361 if (lists == null) { 1362 lists = new ArrayList<Collection<String>>(); 1363 } 1364 lists.add(parseInnerList()); 1365 } else if (parser.getLocalName().equals("map")) { 1366 if (maps == null) { 1367 maps = new ArrayList<Map<String, String>>(); 1368 } 1369 maps.add(parseMap()); 1370 } else { 1371 throwException("Unexpected element: "+parser.getLocalName()); 1372 } 1373 } else if (event == XMLStreamConstants.END_ELEMENT) { 1374 break; 1375 } 1376 } 1377 if (entries != null) { 1378 collectionProperties.put(key, entries); 1379 } 1380 if (lists != null) { 1381 arrayProperties.put(key, lists); 1382 } 1383 if (maps != null) { 1384 listOfStructsProperties.put(key, maps); 1385 } 1386 } 1387 1388 protected Collection<String> parseInnerList() throws XMLStreamException { 1389 Collection<String> entries = new ArrayList<String>(); 1390 while (true) { 1391 int event = parser.next(); 1392 if (event == XMLStreamConstants.START_ELEMENT) { 1393 if (parser.getLocalName().equals("entry")) { 1394 entries.add(parser.getAttributeValue(null, "value")); 1395 jumpToEnd(); 1396 } else { 1397 throwException("Unexpected element: "+parser.getLocalName()); 1398 } 1399 } else if (event == XMLStreamConstants.END_ELEMENT) { 1400 break; 1401 } 1402 } 1403 return entries; 1404 } 1405 1406 protected Map<String, String> parseMap() throws XMLStreamException { 1407 Map<String, String> map = new LinkedHashMap<String, String>(); 1408 while (true) { 1409 int event = parser.next(); 1410 if (event == XMLStreamConstants.START_ELEMENT) { 1411 if (parser.getLocalName().equals("tag")) { 1412 map.put(parser.getAttributeValue(null, "key"), parser.getAttributeValue(null, "value")); 1413 jumpToEnd(); 1414 } else { 1415 throwException("Unexpected element: "+parser.getLocalName()); 1416 } 1417 } else if (event == XMLStreamConstants.END_ELEMENT) { 1418 break; 1419 } 1420 } 1421 return map; 1422 } 1423 1424 protected void throwException(String msg) { 1425 throw new RuntimeException(msg + tr(" (at line {0}, column {1})", parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber())); 1426 } 1427 1113 1428 public String toXML(boolean nopass) { 1114 1429 StringBuilder b = new StringBuilder( 1115 1430 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + … … 1125 1440 if(s == null || !s.equals(r)) { 1126 1441 if(r.contains("\u001e")) 1127 1442 { 1128 b.append(" <collectionkey='");1443 b.append(" <list key='"); 1129 1444 b.append(XmlWriter.encode(p.getKey())); 1130 1445 b.append("'>\n"); 1131 1446 for (String val : r.split("\u001e", -1)) 1132 1447 { 1133 b.append(" <entry value='");1448 b.append(" <entry value='"); 1134 1449 b.append(XmlWriter.encode(val)); 1135 b.append("' />\n");1450 b.append("'/>\n"); 1136 1451 } 1137 b.append(" </collection>\n");1452 b.append(" </list>\n"); 1138 1453 } 1139 1454 else 1140 1455 { 1141 b.append(" <tag key='");1456 b.append(" <tag key='"); 1142 1457 b.append(XmlWriter.encode(p.getKey())); 1143 1458 b.append("' value='"); 1144 1459 b.append(XmlWriter.encode(p.getValue())); 1145 b.append("' />\n");1460 b.append("'/>\n"); 1146 1461 } 1147 1462 } 1148 1463 } 1149 b.append("</preferences>"); 1464 for (Entry<String, Collection<String>> listEntry : collectionProperties.entrySet()) { 1465 b.append(" <list key='").append(XmlWriter.encode(listEntry.getKey())).append("'>\n"); 1466 for (String s : listEntry.getValue()) { 1467 b.append(" <entry value='").append(XmlWriter.encode(s)).append("'/>\n"); 1468 } 1469 b.append(" </list>\n"); 1470 } 1471 for (Entry<String, Collection<Collection<String>>> arrayEntry : arrayProperties.entrySet()) { 1472 b.append(" <list key='").append(XmlWriter.encode(arrayEntry.getKey())).append("'>\n"); 1473 for (Collection<String> list : arrayEntry.getValue()) { 1474 b.append(" <list>\n"); 1475 for (String s : list) { 1476 b.append(" <entry value='").append(XmlWriter.encode(s)).append("'/>\n"); 1477 } 1478 b.append(" </list>\n"); 1479 } 1480 b.append(" </list>\n"); 1481 } 1482 for (Entry<String, Collection<Map<String, String>>> listOfStructsEntry : listOfStructsProperties.entrySet()) { 1483 b.append(" <list key='").append(XmlWriter.encode(listOfStructsEntry.getKey())).append("'>\n"); 1484 for (Map<String, String> struct : listOfStructsEntry.getValue()) { 1485 b.append(" <map>\n"); 1486 for (Entry<String, String> e : struct.entrySet()) { 1487 b.append(" <tag key='").append(XmlWriter.encode(e.getKey())).append("' value='").append(XmlWriter.encode(e.getValue())).append("'/>\n"); 1488 } 1489 b.append(" </map>\n"); 1490 } 1491 b.append(" </list>\n"); 1492 } 1493 b.append("</preferences>\n"); 1150 1494 return b.toString(); 1151 1495 } 1152 1496 } -
src/org/openstreetmap/josm/data/ServerSidePreferences.java
21 21 import java.util.Map.Entry; 22 22 23 23 import javax.swing.JOptionPane; 24 import javax.xml.stream.XMLStreamException; 24 25 25 26 import org.openstreetmap.josm.Main; 26 27 import org.openstreetmap.josm.io.OsmConnection; 27 28 import org.openstreetmap.josm.io.OsmTransferException; 28 29 import org.openstreetmap.josm.tools.Base64; 29 import org.xml.sax.SAXException;30 30 31 31 /** 32 32 * This class tweak the Preferences class to provide server side preference settings, as example … … 170 170 fromXML(in); 171 171 } catch (RuntimeException e) { 172 172 e.printStackTrace(); 173 } catch ( SAXException e) {173 } catch (XMLStreamException e) { 174 174 e.printStackTrace(); 175 175 } 176 176 return res; -
data/preferences.xsd
9 9 <choice minOccurs="0" maxOccurs="unbounded"> 10 10 <element name="tag" type="tns:tag" /> 11 11 <element name="collection" type="tns:collection" /> 12 <element name="list" type="tns:list" /> 12 13 </choice> 13 14 </sequence> 14 15 <attribute name="version" type="string" /> … … 19 20 <attribute name="value" type="string" use="required"/> 20 21 </complexType> 21 22 23 <!-- deprecated: remove mid 2012 --> 22 24 <complexType name="collection"> 23 25 <sequence> 24 26 <choice minOccurs="1" maxOccurs="unbounded"> … … 28 30 <attribute name="key" type="string" use="required" /> 29 31 </complexType> 30 32 33 <complexType name="list"> 34 <choice> 35 <sequence> 36 <element name="entry" type="tns:entry" minOccurs="0" maxOccurs="unbounded"/> 37 </sequence> 38 <sequence> 39 <element name="list" type="tns:slist" minOccurs="0" maxOccurs="unbounded"/> 40 </sequence> 41 <sequence> 42 <element name="map" type="tns:map" minOccurs="0" maxOccurs="unbounded"/> 43 </sequence> 44 </choice> 45 <attribute name="key" type="string" use="required" /> 46 </complexType> 47 48 <complexType name="slist"> 49 <sequence> 50 <element name="entry" type="tns:entry" minOccurs="0" maxOccurs="unbounded"/> 51 </sequence> 52 </complexType> 53 54 <complexType name="map"> 55 <sequence> 56 <element name="tag" type="tns:tag" minOccurs="0" maxOccurs="unbounded"/> 57 </sequence> 58 </complexType> 59 31 60 <complexType name="entry"> 32 61 <attribute name="value" type="string" use="required"/> 33 62 </complexType>
