/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util;
import io.netty.util.internal.
PlatformDependent;
import java.io.
InputStream;
import java.net.
URL;
import java.text.
ParseException;
import java.text.
SimpleDateFormat;
import java.util.
Enumeration;
import java.util.
HashSet;
import java.util.
Map;
import java.util.
Properties;
import java.util.
Set;
import java.util.
TreeMap;
/**
* Retrieves the version information of available Netty artifacts.
* <p>
* This class retrieves the version information from {@code META-INF/io.netty.versions.properties}, which is
* generated in build time. Note that it may not be possible to retrieve the information completely, depending on
* your environment, such as the specified {@link ClassLoader}, the current {@link SecurityManager}.
* </p>
*/
public final class
Version {
private static final
String PROP_VERSION = ".version";
private static final
String PROP_BUILD_DATE = ".buildDate";
private static final
String PROP_COMMIT_DATE = ".commitDate";
private static final
String PROP_SHORT_COMMIT_HASH = ".shortCommitHash";
private static final
String PROP_LONG_COMMIT_HASH = ".longCommitHash";
private static final
String PROP_REPO_STATUS = ".repoStatus";
/**
* Retrieves the version information of Netty artifacts using the current
* {@linkplain Thread#getContextClassLoader() context class loader}.
*
* @return A {@link Map} whose keys are Maven artifact IDs and whose values are {@link Version}s
*/
public static
Map<
String,
Version>
identify() {
return
identify(null);
}
/**
* Retrieves the version information of Netty artifacts using the specified {@link ClassLoader}.
*
* @return A {@link Map} whose keys are Maven artifact IDs and whose values are {@link Version}s
*/
public static
Map<
String,
Version>
identify(
ClassLoader classLoader) {
if (
classLoader == null) {
classLoader =
PlatformDependent.
getContextClassLoader();
}
// Collect all properties.
Properties props = new
Properties();
try {
Enumeration<
URL>
resources =
classLoader.
getResources("META-INF/io.netty.versions.properties");
while (
resources.
hasMoreElements()) {
URL url =
resources.
nextElement();
InputStream in =
url.
openStream();
try {
props.
load(
in);
} finally {
try {
in.
close();
} catch (
Exception ignore) {
// Ignore.
}
}
}
} catch (
Exception ignore) {
// Not critical. Just ignore.
}
// Collect all artifactIds.
Set<
String>
artifactIds = new
HashSet<
String>();
for (
Object o:
props.
keySet()) {
String k = (
String)
o;
int
dotIndex =
k.
indexOf('.');
if (
dotIndex <= 0) {
continue;
}
String artifactId =
k.
substring(0,
dotIndex);
// Skip the entries without required information.
if (!
props.
containsKey(
artifactId +
PROP_VERSION) ||
!
props.
containsKey(
artifactId +
PROP_BUILD_DATE) ||
!
props.
containsKey(
artifactId +
PROP_COMMIT_DATE) ||
!
props.
containsKey(
artifactId +
PROP_SHORT_COMMIT_HASH) ||
!
props.
containsKey(
artifactId +
PROP_LONG_COMMIT_HASH) ||
!
props.
containsKey(
artifactId +
PROP_REPO_STATUS)) {
continue;
}
artifactIds.
add(
artifactId);
}
Map<
String,
Version>
versions = new
TreeMap<
String,
Version>();
for (
String artifactId:
artifactIds) {
versions.
put(
artifactId,
new
Version(
artifactId,
props.
getProperty(
artifactId +
PROP_VERSION),
parseIso8601(
props.
getProperty(
artifactId +
PROP_BUILD_DATE)),
parseIso8601(
props.
getProperty(
artifactId +
PROP_COMMIT_DATE)),
props.
getProperty(
artifactId +
PROP_SHORT_COMMIT_HASH),
props.
getProperty(
artifactId +
PROP_LONG_COMMIT_HASH),
props.
getProperty(
artifactId +
PROP_REPO_STATUS)));
}
return
versions;
}
private static long
parseIso8601(
String value) {
try {
return new
SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").
parse(
value).
getTime();
} catch (
ParseException ignored) {
return 0;
}
}
/**
* Prints the version information to {@link System#err}.
*/
public static void
main(
String[]
args) {
for (
Version v:
identify().
values()) {
System.
err.
println(
v);
}
}
private final
String artifactId;
private final
String artifactVersion;
private final long
buildTimeMillis;
private final long
commitTimeMillis;
private final
String shortCommitHash;
private final
String longCommitHash;
private final
String repositoryStatus;
private
Version(
String artifactId,
String artifactVersion,
long
buildTimeMillis, long
commitTimeMillis,
String shortCommitHash,
String longCommitHash,
String repositoryStatus) {
this.
artifactId =
artifactId;
this.
artifactVersion =
artifactVersion;
this.
buildTimeMillis =
buildTimeMillis;
this.
commitTimeMillis =
commitTimeMillis;
this.
shortCommitHash =
shortCommitHash;
this.
longCommitHash =
longCommitHash;
this.
repositoryStatus =
repositoryStatus;
}
public
String artifactId() {
return
artifactId;
}
public
String artifactVersion() {
return
artifactVersion;
}
public long
buildTimeMillis() {
return
buildTimeMillis;
}
public long
commitTimeMillis() {
return
commitTimeMillis;
}
public
String shortCommitHash() {
return
shortCommitHash;
}
public
String longCommitHash() {
return
longCommitHash;
}
public
String repositoryStatus() {
return
repositoryStatus;
}
@
Override
public
String toString() {
return
artifactId + '-' +
artifactVersion + '.' +
shortCommitHash +
("clean".
equals(
repositoryStatus)? "" : " (repository: " +
repositoryStatus + ')');
}
}