001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data;
003
004import static org.openstreetmap.josm.tools.I18n.tr;
005
006import java.io.BufferedReader;
007import java.io.IOException;
008import java.io.InputStreamReader;
009import java.io.OutputStreamWriter;
010import java.io.PrintWriter;
011import java.io.Reader;
012import java.io.StringReader;
013import java.net.HttpURLConnection;
014import java.net.MalformedURLException;
015import java.net.URL;
016import java.net.URLConnection;
017
018import javax.swing.JOptionPane;
019import javax.xml.stream.XMLStreamException;
020
021import org.openstreetmap.josm.Main;
022import org.openstreetmap.josm.io.OsmConnection;
023import org.openstreetmap.josm.tools.Base64;
024import org.openstreetmap.josm.tools.Utils;
025
026/**
027 * This class tweak the Preferences class to provide server side preference settings, as example
028 * used in the applet version.
029 *
030 * @author Imi
031 */
032public class ServerSidePreferences extends Preferences {
033    public static class MissingPassword extends Exception{
034        public String realm;
035        public MissingPassword(String r) {
036            realm = r;
037        }
038    }
039
040    private final Connection connection;
041
042    private class Connection extends OsmConnection {
043        URL serverUrl;
044        public Connection(URL serverUrl) {
045            this.serverUrl = serverUrl;
046        }
047        public String download() throws MissingPassword {
048            try {
049                Main.info("reading preferences from "+serverUrl);
050                URLConnection con = serverUrl.openConnection();
051                String username = get("applet.username");
052                String password = get("applet.password");
053                if(password.isEmpty() && username.isEmpty()) {
054                    con.addRequestProperty("Authorization", "Basic "+Base64.encode(username+":"+password));
055                }
056                con.connect();
057                if(username.isEmpty() && con instanceof HttpURLConnection
058                        && ((HttpURLConnection) con).getResponseCode()
059                        == HttpURLConnection.HTTP_UNAUTHORIZED) {
060                    String t = ((HttpURLConnection) con).getHeaderField("WWW-Authenticate");
061                    t = t.replace("Basic realm=\"","").replace("\"","");
062                    throw new MissingPassword(t);
063                }
064                BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
065                StringBuilder b = new StringBuilder();
066                try {
067                    for (String line = reader.readLine(); line != null; line = reader.readLine()) {
068                        b.append(line);
069                        b.append("\n");
070                    }
071                } finally {
072                    reader.close();
073                }
074                if (con instanceof HttpURLConnection) {
075                    ((HttpURLConnection) con).disconnect();
076                }
077                return b.toString();
078            } catch (IOException e) {
079                Main.error(e);
080                e.printStackTrace();
081            }
082            return null;
083        }
084        public void upload(String s) {
085            try {
086                URL u = new URL(getPreferencesDir());
087                Main.info("uploading preferences to "+u);
088                HttpURLConnection con = (HttpURLConnection)u.openConnection();
089                String username = get("applet.username");
090                String password = get("applet.password");
091                if(password.isEmpty() && username.isEmpty()) {
092                    con.addRequestProperty("Authorization", "Basic "+Base64.encode(username+":"+password));
093                }
094                con.setRequestMethod("POST");
095                con.setDoOutput(true);
096                con.connect();
097                PrintWriter out = new PrintWriter(new OutputStreamWriter(con.getOutputStream()));
098                out.println(s);
099                Utils.close(out);
100                Utils.close(con.getInputStream());
101                con.disconnect();
102                JOptionPane.showMessageDialog(
103                        Main.parent,
104                        tr("Preferences stored on {0}", u.getHost()),
105                        tr("Information"),
106                        JOptionPane.INFORMATION_MESSAGE
107                        );
108            } catch (Exception e) {
109                e.printStackTrace();
110                JOptionPane.showMessageDialog(
111                        Main.parent,
112                        tr("Could not upload preferences. Reason: {0}", e.getMessage()),
113                        tr("Error"),
114                        JOptionPane.ERROR_MESSAGE
115                        );
116            }
117        }
118    }
119
120    public ServerSidePreferences(URL serverUrl) {
121        Connection connection = null;
122        try {
123            connection = new Connection(new URL(serverUrl+"user/preferences"));
124        } catch (MalformedURLException e) {
125            e.printStackTrace();
126            JOptionPane.showMessageDialog(
127                    Main.parent,
128                    tr("Could not load preferences from server."),
129                    tr("Error"),
130                    JOptionPane.ERROR_MESSAGE
131                    );
132        }
133        this.connection = connection;
134    }
135
136    @Override public String getPreferencesDir() {
137        return connection.serverUrl.toString();
138    }
139
140    /**
141     * Do nothing on load. Preferences are loaded with download().
142     */
143    @Override public void load() {
144    }
145
146    /**
147     * Do nothing on save. Preferences are uploaded using upload().
148     */
149    @Override public void save() {
150    }
151
152    public void download(String userName, String password) {
153        if (!properties.containsKey("applet.username") && userName != null) {
154            properties.put("applet.username", userName);
155        }
156        if (!properties.containsKey("applet.password") && password != null) {
157            properties.put("applet.password", password);
158        }
159        try {
160            download();
161        } catch (MissingPassword e) {
162            Main.warn(e);
163        }
164    }
165
166    public boolean download() throws MissingPassword {
167        resetToDefault();
168        String cont = connection.download();
169        if (cont == null) return false;
170        Reader in = new StringReader(cont);
171        boolean res = false;
172        try {
173            fromXML(in);
174        } catch (RuntimeException e) {
175            e.printStackTrace();
176        } catch (XMLStreamException e) {
177            e.printStackTrace();
178        }
179        return res;
180    }
181
182    /**
183     * Use this instead of save() for the ServerSidePreferences, since uploads
184     * are costly while save is called often.
185     *
186     * This is triggered by an explicit menu option.
187     */
188    public void upload() {
189        connection.upload(toXML(true));
190    }
191}