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.IOException;
007import java.io.InputStream;
008import java.util.Map.Entry;
009import java.util.Optional;
010import java.util.Properties;
011
012import org.openstreetmap.josm.tools.LanguageInfo;
013import org.openstreetmap.josm.tools.Logging;
014import org.openstreetmap.josm.tools.PlatformManager;
015import org.openstreetmap.josm.tools.Utils;
016
017/**
018 * Provides basic information about the currently used JOSM build.
019 * @since 2358
020 */
021public class Version {
022    /** constant to indicate that the current build isn't assigned a JOSM version number */
023    public static final int JOSM_UNKNOWN_VERSION = 0;
024
025    /** the unique instance */
026    private static Version instance;
027
028    /**
029     * Replies the unique instance of the version information
030     *
031     * @return the unique instance of the version information
032     */
033    public static synchronized Version getInstance() {
034        if (instance == null) {
035            instance = new Version();
036            instance.init();
037        }
038        return instance;
039    }
040
041    private int version;
042    private String releaseDescription;
043    private String time;
044    private String buildName;
045    private boolean isLocalBuild;
046
047    /**
048     * Initializes the version infos from the revision resource file
049     *
050     * @param revisionInfo the revision info from a revision resource file as InputStream
051     */
052    protected void initFromRevisionInfo(InputStream revisionInfo) {
053        if (revisionInfo == null) {
054            this.releaseDescription = tr("UNKNOWN");
055            this.version = JOSM_UNKNOWN_VERSION;
056            this.time = null;
057            return;
058        }
059
060        Properties properties = new Properties();
061        try {
062            properties.load(revisionInfo);
063        } catch (IOException e) {
064            Logging.log(Logging.LEVEL_WARN, tr("Error reading revision info from revision file: {0}", e.getMessage()), e);
065        }
066        String value = Optional.ofNullable(properties.getProperty("Revision")).orElse("").trim();
067        if (!value.isEmpty()) {
068            try {
069                version = Integer.parseInt(value);
070            } catch (NumberFormatException e) {
071                version = 0;
072                Logging.warn(tr("Unexpected JOSM version number in revision file, value is ''{0}''", value));
073            }
074        } else {
075            version = JOSM_UNKNOWN_VERSION;
076        }
077
078        // the last changed data
079        //
080        time = properties.getProperty("Last Changed Date");
081        if (time == null) {
082            time = properties.getProperty("Build-Date");
083        }
084
085        // is this a local build ?
086        //
087        isLocalBuild = "true".equalsIgnoreCase(
088                Optional.ofNullable(properties.getProperty("Is-Local-Build")).orElse("").trim());
089
090        // is this a specific build ?
091        //
092        buildName = Optional.ofNullable(properties.getProperty("Build-Name")).orElse("").trim();
093
094        // the revision info
095        //
096        StringBuilder sb = new StringBuilder();
097        for (Entry<Object, Object> property: properties.entrySet()) {
098            sb.append(property.getKey()).append(':').append(property.getValue()).append('\n');
099        }
100        releaseDescription = sb.toString();
101    }
102
103    /**
104     * Initializes version info
105     */
106    public void init() {
107        try (InputStream stream = Utils.getResourceAsStream(getClass(), "/REVISION")) {
108            if (stream == null) {
109                Logging.warn(tr("The revision file ''/REVISION'' is missing."));
110                version = 0;
111                releaseDescription = "";
112                return;
113            }
114            initFromRevisionInfo(stream);
115        } catch (IOException e) {
116            Logging.warn(e);
117        }
118    }
119
120    /**
121     * Replies the version string. Either the SVN revision "1234" (as string) or the
122     * the I18n equivalent of "UNKNOWN".
123     *
124     * @return the JOSM version
125     */
126    public String getVersionString() {
127        return version == 0 ? tr("UNKNOWN") : Integer.toString(version);
128    }
129
130    /**
131     * Replies a text with the release attributes
132     *
133     * @return a text with the release attributes
134     */
135    public String getReleaseAttributes() {
136        return releaseDescription;
137    }
138
139    /**
140     * Replies the build date as string
141     *
142     * @return the build date as string
143     */
144    public String getTime() {
145        return time;
146    }
147
148    /**
149     * Replies the JOSM version. Replies {@link #JOSM_UNKNOWN_VERSION} if the version isn't known.
150     * @return the JOSM version
151     */
152    public int getVersion() {
153        return version;
154    }
155
156    /**
157     * Replies true if this is a local build, i.e. an unofficial development build.
158     *
159     * @return true if this is a local build, i.e. an unofficial development build.
160     */
161    public boolean isLocalBuild() {
162        return isLocalBuild;
163    }
164
165    /**
166     * Returns the User-Agent string
167     * @return The User-Agent
168     */
169    public String getAgentString() {
170        return getAgentString(true);
171    }
172
173    /**
174     * Returns the User-Agent string, with or without OS details
175     * @param includeOsDetails Append Operating System details at the end of the User-Agent
176     * @return The User-Agent
177     * @since 5956
178     */
179    public String getAgentString(boolean includeOsDetails) {
180        int v = getVersion();
181        String s = (v == JOSM_UNKNOWN_VERSION) ? "UNKNOWN" : Integer.toString(v);
182        if (buildName != null && !buildName.isEmpty()) {
183            s += ' ' + buildName;
184        }
185        if (isLocalBuild() && v != JOSM_UNKNOWN_VERSION) {
186            s += " SVN";
187        }
188        String result = "JOSM/1.5 ("+ s+' '+LanguageInfo.getJOSMLocaleCode()+')';
189        if (includeOsDetails) {
190            result += ' ' + PlatformManager.getPlatform().getOSDescription();
191        }
192        return result;
193    }
194
195    /**
196     * Returns the full User-Agent string
197     * @return The User-Agent
198     * @since 5868
199     */
200    public String getFullAgentString() {
201        return getAgentString() + " Java/"+Utils.getSystemProperty("java.version");
202    }
203}