package net.techreadiness.customer.action; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashSet; import java.util.Properties; import java.util.TimeZone; import java.util.TreeSet; import java.util.jar.Attributes; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.jar.Manifest; import javax.inject.Inject; import javax.servlet.ServletContext; import org.apache.commons.io.FileUtils; import org.apache.commons.io.filefilter.IOFileFilter; import org.apache.commons.io.filefilter.NameFileFilter; import org.apache.commons.io.filefilter.TrueFileFilter; import org.apache.commons.lang3.StringUtils; import org.apache.struts2.convention.annotation.Result; import org.apache.struts2.convention.annotation.Results; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.Ordering; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionSupport; @Results({ @Result(name = Action.SUCCESS, location = "/WEB-INF/version.jsp") }) public class VersionAction extends ActionSupport { private final Logger log = LoggerFactory.getLogger(VersionAction.class); @Inject private ServletContext context; class PropertiesComparator implements Comparator<Properties> { @Override public int compare(Properties p1, Properties p2) { Collection<String> properties = Arrays.asList("groupId", "artifactId", "version"); for (String property : properties) { int diff = Ordering.natural().compare(p1.getProperty(property), p2.getProperty(property)); if (diff != 0) { return diff; } } return 0; } } private static final long serialVersionUID = 1L; private Collection<URL> resources; private Collection<URI> pomResources; private Collection<Properties> versions; private Collection<Properties> trtVersions; private Properties application; private Date buildDate; @Override public String execute() { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { resources = Collections.list(classLoader.getResources("META-INF/maven")); } catch (IOException e2) { String msg = "Failed to list Maven package resources"; log.error(msg); addActionError(msg); } pomResources = new HashSet<>(); for (URL url : resources) { String path; try { path = URLDecoder.decode(url.getPath(), "UTF-8"); if (path.startsWith("file:")) { path = path.substring(5); } if (path.indexOf('!') > 0) { path = path.substring(0, path.indexOf('!')); } File file = new File(path); if (file.isDirectory()) { IOFileFilter fileFilter = new NameFileFilter("pom.properties"); Collection<File> files = FileUtils.listFiles(file, fileFilter, TrueFileFilter.INSTANCE); for (File child : files) { pomResources.add(child.toURI()); } } else { JarEntry entry; try (JarInputStream jarStream = new JarInputStream(new FileInputStream(file))) { while ((entry = jarStream.getNextJarEntry()) != null) { String name = entry.getName(); if (!entry.isDirectory() && name.startsWith("META-INF/maven") && name.endsWith("pom.properties")) { pomResources.add(classLoader.getResource(name).toURI()); } } } catch (IOException | URISyntaxException e) { String msg = "Failed to extract Maven property resource from jar"; log.error(msg); addActionError(msg); } } } catch (UnsupportedEncodingException e) { String msg = "Failed to decode path to Maven resource location"; log.error(msg); addActionError(msg); } } versions = new TreeSet<>(new PropertiesComparator()); trtVersions = new TreeSet<>(new PropertiesComparator()); for (URI properties : pomResources) { Properties p = new Properties(); try (InputStream stream = properties.toURL().openStream()) { p.load(stream); versions.add(p); if (p.getProperty("groupId").startsWith("net.techreadiness")) { trtVersions.add(p); } } catch (IOException e) { String msg = "Failed to read Maven property information"; log.error(msg); addActionError(msg); } } String basePath = context.getRealPath("/"); try (FileInputStream manifestInputStream = new FileInputStream(new File(basePath, "META-INF/MANIFEST.MF"))) { Attributes manifest = new Manifest(manifestInputStream).getMainAttributes(); application = new Properties(); application.setProperty("groupId", manifest.getValue("Implementation-Vendor-Id")); application.setProperty("artifactId", manifest.getValue("Implementation-Title")); application.setProperty("version", manifest.getValue("Implementation-Version")); application.setProperty("buildNumber", manifest.getValue("Build-Number")); String buildTime = manifest.getValue("Build-Id"); if (StringUtils.isNotBlank(buildTime)) { DateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss"); format.setTimeZone(TimeZone.getTimeZone("America/Chicago")); buildDate = format.parse(buildTime); } } catch (IOException | ParseException e) { String msg = "Failed to read application manifest"; log.error(msg); addActionError(msg); } return SUCCESS; } public Collection<Properties> getVersions() { return versions; } public Collection<Properties> getTrtVersions() { return trtVersions; } public Properties getApplication() { return application; } public Date getBuildDate() { return buildDate; } }