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}