/*
* This file is part of the Illarion project.
*
* Copyright © 2015 - Illarion e.V.
*
* Illarion is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Illarion is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
package illarion.common.util;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.net.URL;
import java.util.Enumeration;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
/**
* This class is used to fetch the version number of the specified application.
*
* @author Martin Karing <nitram@illarion.org>
*/
@SuppressWarnings("ALL")
public class AppIdent implements Externalizable {
/**
* Serialization UID.
*/
public static final long serialVersionUID = 1L;
/**
* The name of the application.
*/
@Nonnull
private String appName;
/**
* The version of the application.
*/
@Nonnull
private String appVersion;
/**
* Create a new instance of the application identification class. Specify the name and the version of the
* application.
*
* @param appName the name of the application
* @param appVersion the version of the application
*/
public AppIdent(@Nonnull String appName, @Nonnull String appVersion) {
this.appName = appName;
this.appVersion = appVersion;
}
/**
* Constructor for deserialization.
*/
public AppIdent() {
}
/**
* Create a new instance of the application identification class and specify the name of the application. The
* class will try to fetch the version from the meta information that are attached to the class.
*
* @param appName the name of the application
*/
public AppIdent(@Nonnull String appName) {
this.appName = appName;
@Nullable String foundVersion = null;
try {
Enumeration<URL> resources = AppIdent.class.getClassLoader().getResources("META-INF/MANIFEST.MF");
while (resources.hasMoreElements()) {
InputStream stream = null;
try {
URL currentResource = resources.nextElement();
stream = currentResource.openStream();
Manifest manifest = new Manifest(currentResource.openStream());
Attributes mainAttribs = manifest.getMainAttributes();
if (appName.equals(mainAttribs.getValue("Implementation-Title"))) {
foundVersion = mainAttribs.getValue("Implementation-Version");
break;
}
} catch (@Nonnull IOException ex) {
// nothing
} finally {
if (stream != null) {
try {
stream.close();
} catch (@Nonnull IOException ex) {
// nothing
}
}
}
}
} catch (@Nonnull IOException ex) {
// nothing
}
if ((foundVersion == null) || "unknown".equals(foundVersion)) {
appVersion = "";
} else {
appVersion = foundVersion;
}
}
/**
* Get the name of the application.
*
* @return the name of the application
*/
@Nonnull
@Contract(pure = true)
public String getApplicationName() {
return appName;
}
/**
* Get the version of the application.
*
* @return the version of the application or a empty string in case the version is unknown
*/
@Nonnull
@Contract(pure = true)
public String getApplicationVersion() {
return appVersion;
}
/**
* Get the version of the application stripped from all appending data that identifies the exact version.
*
* @return the application root version
*/
@Nonnull
@Contract(pure = true)
public String getApplicationRootVersion() {
int indexOfSeparator = appVersion.indexOf('-');
if (indexOfSeparator == -1) {
return appVersion;
}
return appVersion.substring(0, indexOfSeparator);
}
/**
* Get the amount of commit that are applied to this version of the application since the release.
*
* @return the commit count
*/
@Contract(pure = true)
public int getCommitCount() {
int indexOfSeparator = appVersion.indexOf('-');
if (indexOfSeparator == -1) {
return 0;
}
int indexSecondSeparator = appVersion.indexOf('-', indexOfSeparator + 1);
if (indexSecondSeparator == -1) {
return 0;
}
try {
return Integer.parseInt(appVersion.substring(indexOfSeparator + 1, indexSecondSeparator));
} catch (@Nonnull NumberFormatException e) {
return 0;
}
}
/**
* Get the name of the application and the version of the application on case its known.
*
* @return the identifier of the application
*/
@Nonnull
@Contract(pure = true)
public String getApplicationIdentifier() {
if (appVersion.isEmpty()) {
return appName;
}
return appName + ' ' + appVersion;
}
@Override
public void writeExternal(@Nonnull ObjectOutput out) throws IOException {
out.writeLong(serialVersionUID);
out.writeObject(appName);
out.writeObject(appVersion);
}
@Override
public void readExternal(@Nonnull ObjectInput in) throws IOException, ClassNotFoundException {
long version = in.readLong();
if (version == 1L) {
appName = in.readObject().toString();
appVersion = in.readObject().toString();
} else {
throw new ClassNotFoundException("Class version invalid. Found: " + Long.toString(version) +
" expected: 1");
}
}
}