/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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 org.apache.isis.viewer.wicket.ui.components.about; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Map.Entry; import java.util.Set; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.jar.Manifest; import com.google.common.base.CharMatcher; import com.google.common.base.Splitter; import com.google.common.collect.Lists; import org.apache.isis.core.commons.lang.CloseableExtensions; import org.apache.isis.viewer.wicket.model.models.ModelAbstract; public class JarManifestModel extends ModelAbstract<JarManifestModel> { private static final long serialVersionUID = 1L; private static final List<String> VERSION_KEY_CANDIDATES = Arrays.asList("Implementation-Version", "Build-Time"); private String aboutMessage; private final List<JarManifestAttributes> manifests = Lists.newArrayList(); /** * @param aboutMessage * @param metaInfManifestIs provide using <tt>getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF")</tt> */ public JarManifestModel(String aboutMessage, InputStream metaInfManifestIs) { this.aboutMessage = aboutMessage; Manifest manifest; try { manifest = new Manifest(metaInfManifestIs); manifests.add(JarManifestAttributes.jarName("Web archive (war file)")); manifests.add(JarManifestAttributes.jarUrl(null)); addAttributes(manifest, manifests); // append the version if able to guess String versionIfAny = guessVersion(manifest); this.aboutMessage = this.aboutMessage + (versionIfAny != null? "\n\n" + versionIfAny: ""); } catch (Exception ex) { // ignore } finally { CloseableExtensions.closeSafely(metaInfManifestIs); } Enumeration<?> resEnum; try { resEnum = Thread.currentThread().getContextClassLoader().getResources(JarFile.MANIFEST_NAME); } catch (IOException e) { return; } final List<JarManifest> jarManifests = Lists.newArrayList(); while (resEnum.hasMoreElements()) { URL url = (URL)resEnum.nextElement(); JarManifest jarManifest = new JarManifest(url); jarManifests.add(jarManifest); InputStream is = null; try { is = url.openStream(); if (is != null) { manifest = new Manifest(is); jarManifest.addAttributesFrom(manifest); } } catch(Exception e3) { // ignore } finally { CloseableExtensions.closeSafely(is); } } Collections.sort(jarManifests); for (JarManifest jarManifest : jarManifests) { jarManifest.addAttributesTo(manifests); } } private static class JarManifest implements Comparable<JarManifest> { private final List<JarManifestAttributes> attributes = Lists.newArrayList(); private final URL url; private JarName jarName; public JarManifest(URL url) { this.url = url; jarName = asJarName(url); } void addAttributesFrom(Manifest manifest) { addAttributes(manifest, attributes); } void addAttributesTo(List<JarManifestAttributes> manifests) { manifests.add(JarManifestAttributes.jarName(jarName.name)); manifests.add(JarManifestAttributes.jarUrl(url)); manifests.addAll(attributes); } @Override public int compareTo(JarManifest o) { return jarName.compareTo(o.jarName); } } static class JarName implements Comparable<JarName>{ enum Type { CLASSES, JAR, OTHER } Type type; String name; JarName(Type type, String name) { this.type = type; this.name = name; } @Override public int compareTo(JarName o) { int x = type.compareTo(o.type); if(x != 0) return x; return name.compareTo(o.name); } } private static JarName asJarName(URL url) { final String path = url.getPath(); // strip off the meta-inf String strippedPath = stripSuffix(path, "/META-INF/MANIFEST.MF"); strippedPath = stripSuffix(strippedPath, "!"); // split the path into parts, and reverse List<String> parts = Lists.newArrayList(Splitter.on(CharMatcher.anyOf("/\\")).split(strippedPath)); Collections.reverse(parts); // searching from the end, return the jar name if possible for (String part : parts) { if(part.endsWith(".jar")) { return new JarName(JarName.Type.JAR, part); } } // see if running in an IDE, under target*/classes; return the part prior to that. if(parts.size()>=3) { if(parts.get(0).equals("classes") && parts.get(1).startsWith("target")) { return new JarName(JarName.Type.CLASSES, parts.get(2)); } } // otherwise, return the stripped path return new JarName(JarName.Type.OTHER, strippedPath); } public static String stripSuffix(String path, String suffix) { int indexOf = path.indexOf(suffix); if(indexOf != -1) { path = path.substring(0, indexOf); } return path; } static void addAttributes(Manifest manifest, List<JarManifestAttributes> attributes) { final Attributes mainAttribs = manifest.getMainAttributes(); Set<Entry<Object, Object>> entrySet = mainAttribs.entrySet(); for (Entry<Object, Object> entry : entrySet) { JarManifestAttributes attribute = JarManifestAttributes.attribute(entry); attributes.add(attribute); } } private static String guessVersion(Manifest manifest) { final Attributes mainAttribs = manifest.getMainAttributes(); Set<Entry<Object, Object>> entrySet = mainAttribs.entrySet(); for (String candidate : VERSION_KEY_CANDIDATES) { for (Entry<Object, Object> entry : entrySet) { if(candidate.equals(entry.getKey().toString())) { return entry.getValue().toString(); } } } return null; } @Override protected JarManifestModel load() { return this; } @Override public void setObject(JarManifestModel ex) { // no-op } public String getAboutMessage() { return aboutMessage; } public List<JarManifestAttributes> getDetail() { return manifests; } }