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.net.URL; 009import java.util.HashMap; 010import java.util.Map; 011import java.util.Map.Entry; 012import java.util.regex.Matcher; 013import java.util.regex.Pattern; 014 015import org.openstreetmap.josm.Main; 016import org.openstreetmap.josm.tools.LanguageInfo; 017import org.openstreetmap.josm.tools.Utils; 018 019/** 020 * Provides basic information about the currently used JOSM build. 021 * 022 */ 023public class Version { 024 /** constant to indicate that the current build isn't assigned a JOSM version number */ 025 static public final int JOSM_UNKNOWN_VERSION = 0; 026 027 /** the unique instance */ 028 private static Version instance; 029 030 /** 031 * Load the specified resource as string. 032 * 033 * @param resource the resource url to load 034 * @return the content of the resource file; null, if an error occurred 035 */ 036 static public String loadResourceFile(URL resource) { 037 if (resource == null) return null; 038 String s = null; 039 try { 040 BufferedReader in = Utils.openURLReader(resource); 041 StringBuffer sb = new StringBuffer(); 042 try { 043 for (String line = in.readLine(); line != null; line = in.readLine()) { 044 sb.append(line).append("\n"); 045 } 046 } finally { 047 Utils.close(in); 048 } 049 s = sb.toString(); 050 } catch (IOException e) { 051 Main.error(tr("Failed to load resource ''{0}'', error is {1}.", resource.toString(), e.toString())); 052 e.printStackTrace(); 053 } 054 return s; 055 } 056 057 /** 058 * Replies the unique instance of the version information 059 * 060 * @return the unique instance of the version information 061 */ 062 063 static public Version getInstance() { 064 if (instance == null) { 065 instance = new Version(); 066 instance.init(); 067 } 068 return instance; 069 } 070 071 private int version; 072 private String releaseDescription; 073 private String time; 074 private String buildName; 075 private boolean isLocalBuild; 076 077 protected Map<String, String> parseManifestStyleFormattedString(String content) { 078 Map<String, String> properties = new HashMap<String, String>(); 079 if (content == null) return properties; 080 Pattern p = Pattern.compile("^([^:]+):(.*)$"); 081 for (String line: content.split("\n")) { 082 if (line == null || line.trim().isEmpty()) { 083 continue; 084 } 085 if (line.matches("^\\s*#.*$")) { 086 continue; 087 } 088 Matcher m = p.matcher(line); 089 if (m.matches()) { 090 properties.put(m.group(1), m.group(2)); 091 } 092 } 093 return properties; 094 } 095 096 /** 097 * Initializes the version infos from the revision resource file 098 * 099 * @param revisionInfo the revision info loaded from a revision resource file 100 */ 101 protected void initFromRevisionInfo(String revisionInfo) { 102 if (revisionInfo == null) { 103 this.releaseDescription = tr("UNKNOWN"); 104 this.version = JOSM_UNKNOWN_VERSION; 105 this.time = null; 106 return; 107 } 108 109 Map<String, String> properties = parseManifestStyleFormattedString(revisionInfo); 110 String value = properties.get("Revision"); 111 if (value != null) { 112 value = value.trim(); 113 try { 114 version = Integer.parseInt(value); 115 } catch(NumberFormatException e) { 116 version = 0; 117 Main.warn(tr("Unexpected JOSM version number in revision file, value is ''{0}''", value)); 118 } 119 } else { 120 version = JOSM_UNKNOWN_VERSION; 121 } 122 123 // the last changed data 124 // 125 time = properties.get("Last Changed Date"); 126 if (time == null) { 127 time = properties.get("Build-Date"); 128 } 129 130 // is this a local build ? 131 // 132 isLocalBuild = false; 133 value = properties.get("Is-Local-Build"); 134 if (value != null && value.trim().equalsIgnoreCase("true")) { 135 isLocalBuild = true; 136 } 137 138 // is this a specific build ? 139 // 140 buildName = null; 141 value = properties.get("Build-Name"); 142 if (value != null && !value.trim().isEmpty()) { 143 buildName = value.trim(); 144 } 145 146 // the revision info 147 // 148 StringBuffer sb = new StringBuffer(); 149 for(Entry<String,String> property: properties.entrySet()) { 150 sb.append(property.getKey()).append(":").append(property.getValue()).append("\n"); 151 } 152 releaseDescription = sb.toString(); 153 } 154 155 /** 156 * Initializes version info 157 */ 158 public void init() { 159 URL u = Main.class.getResource("/REVISION"); 160 if (u == null) { 161 Main.warn(tr("The revision file ''/REVISION'' is missing.")); 162 version = 0; 163 releaseDescription = ""; 164 return; 165 } 166 initFromRevisionInfo(loadResourceFile(u)); 167 } 168 169 /** 170 * Replies the version string. Either the SVN revision "1234" (as string) or the 171 * the I18n equivalent of "UNKNOWN". 172 * 173 * @return the JOSM version 174 */ 175 public String getVersionString() { 176 return version == 0 ? tr("UNKNOWN") : Integer.toString(version); 177 } 178 179 /** 180 * Replies a text with the release attributes 181 * 182 * @return a text with the release attributes 183 */ 184 public String getReleaseAttributes() { 185 return releaseDescription; 186 } 187 188 /** 189 * Replies the build date as string 190 * 191 * @return the build date as string 192 */ 193 public String getTime() { 194 return time; 195 } 196 197 /** 198 * Replies the JOSM version. Replies {@link #JOSM_UNKNOWN_VERSION} if the version isn't known. 199 * @return the JOSM version 200 */ 201 public int getVersion() { 202 return version; 203 } 204 205 /** 206 * Replies true if this is a local build, i.e. an inofficial development build. 207 * 208 * @return true if this is a local build, i.e. an inofficial development build. 209 */ 210 public boolean isLocalBuild() { 211 return isLocalBuild; 212 } 213 214 /** 215 * Returns the User-Agent string 216 * @return The User-Agent 217 */ 218 public String getAgentString() { 219 return getAgentString(true); 220 } 221 222 /** 223 * Returns the User-Agent string, with or without OS details 224 * @param includeOsDetails Append Operating System details at the end of the User-Agent 225 * @return The User-Agent 226 * @since 5956 227 */ 228 public String getAgentString(boolean includeOsDetails) { 229 int v = getVersion(); 230 String s = (v == JOSM_UNKNOWN_VERSION) ? "UNKNOWN" : Integer.toString(v); 231 if (buildName != null) { 232 s += " " + buildName; 233 } 234 if (isLocalBuild() && v != JOSM_UNKNOWN_VERSION) { 235 s += " SVN"; 236 } 237 String result = "JOSM/1.5 ("+ s+" "+LanguageInfo.getJOSMLocaleCode()+")"; 238 if (includeOsDetails && Main.platform != null) { 239 result += " " + Main.platform.getOSDescription(); 240 } 241 return result; 242 } 243 244 /** 245 * Returns the full User-Agent string 246 * @return The User-Agent 247 * @since 5868 248 */ 249 public String getFullAgentString() { 250 return getAgentString() + " Java/"+System.getProperty("java.version"); 251 } 252}