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