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