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