001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.preferences; 003 004import java.io.PrintWriter; 005import java.util.Collection; 006import java.util.List; 007import java.util.Map; 008import java.util.stream.Stream; 009 010import org.openstreetmap.josm.Main; 011import org.openstreetmap.josm.data.Version; 012import org.openstreetmap.josm.io.XmlWriter; 013 014/** 015 * Write preferences to XML. 016 * @since 9823 017 */ 018public class PreferencesWriter extends XmlWriter implements SettingVisitor { 019 private final boolean noPassword; 020 private final boolean defaults; 021 private String key; 022 023 /** 024 * Construct new {@code PreferencesWriter}. 025 * @param out the {@link PrintWriter} 026 * @param noPassword if password must be excluded 027 * @param defaults true, if default values are converted to XML, false for regular preferences 028 */ 029 public PreferencesWriter(PrintWriter out, boolean noPassword, boolean defaults) { 030 super(out); 031 this.noPassword = noPassword; 032 this.defaults = defaults; 033 } 034 035 /** 036 * Write preferences. 037 * 038 * @param settings preferences settings to write 039 */ 040 public void write(Collection<Map.Entry<String, Setting<?>>> settings) { 041 write(settings.stream()); 042 } 043 044 /** 045 * Write preferences. 046 * 047 * @param settings preferences settings to write as stream. 048 */ 049 public void write(Stream<Map.Entry<String, Setting<?>>> settings) { 050 out.write(String.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>%n")); 051 String rootElement = defaults ? "preferences-defaults" : "preferences"; 052 out.write(String.format("<%s xmlns='%s/preferences-1.0'", rootElement, Main.getXMLBase())); 053 if (defaults) { 054 out.write(" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'"); 055 } 056 out.write(String.format(" version='%d'>%n", Version.getInstance().getVersion())); 057 settings.forEachOrdered(e -> { 058 setKey(e.getKey()); 059 e.getValue().visit(this); 060 }); 061 out.write(String.format("</%s>%n", rootElement)); 062 } 063 064 private void setKey(String key) { 065 this.key = key; 066 } 067 068 private void addTime(Setting<?> setting) { 069 if (defaults) { 070 Long time = setting.getTime(); 071 if (time == null) 072 throw new IllegalStateException(); 073 out.write("' time='" + time); 074 } 075 } 076 077 private void addDefaults() { 078 out.write(String.format("' xsi:nil='true'/>%n")); 079 } 080 081 @Override 082 public void visit(StringSetting setting) { 083 if (noPassword && "osm-server.password".equals(key)) 084 return; // do not store plain password. 085 out.write(" <tag key='" + XmlWriter.encode(key)); 086 addTime(setting); 087 if (setting.getValue() != null) { 088 out.write(String.format("' value='%s'/>%n", XmlWriter.encode(setting.getValue()))); 089 } else if (defaults) { 090 addDefaults(); 091 } else { 092 throw new NullPointerException(); 093 } 094 } 095 096 @Override 097 public void visit(ListSetting setting) { 098 out.write(" <list key='" + XmlWriter.encode(key)); 099 addTime(setting); 100 if (setting.getValue() != null) { 101 out.write(String.format("'>%n")); 102 for (String s : setting.getValue()) { 103 out.write(String.format(" <entry value='%s'/>%n", XmlWriter.encode(s))); 104 } 105 out.write(String.format(" </list>%n")); 106 } else if (defaults) { 107 addDefaults(); 108 } else { 109 throw new NullPointerException(); 110 } 111 } 112 113 @Override 114 public void visit(ListListSetting setting) { 115 out.write(" <lists key='" + XmlWriter.encode(key)); 116 addTime(setting); 117 if (setting.getValue() != null) { 118 out.write(String.format("'>%n")); 119 for (List<String> list : setting.getValue()) { 120 out.write(String.format(" <list>%n")); 121 for (String s : list) { 122 out.write(String.format(" <entry value='%s'/>%n", encode(s))); 123 } 124 out.write(String.format(" </list>%n")); 125 } 126 out.write(String.format(" </lists>%n")); 127 } else if (defaults) { 128 addDefaults(); 129 } else { 130 throw new NullPointerException(); 131 } 132 } 133 134 @Override 135 public void visit(MapListSetting setting) { 136 out.write(" <maps key='" + encode(key)); 137 addTime(setting); 138 if (setting.getValue() != null) { 139 out.write(String.format("'>%n")); 140 for (Map<String, String> struct : setting.getValue()) { 141 out.write(String.format(" <map>%n")); 142 for (Map.Entry<String, String> e : struct.entrySet()) { 143 out.write(String.format(" <tag key='%s' value='%s'/>%n", encode(e.getKey()), encode(e.getValue()))); 144 } 145 out.write(String.format(" </map>%n")); 146 } 147 out.write(String.format(" </maps>%n")); 148 } else if (defaults) { 149 addDefaults(); 150 } else { 151 throw new NullPointerException(); 152 } 153 } 154}