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}