You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/03/13 00:32:22 UTC

[6/38] git commit: ISIS-360: about message shows version and other manifest attributes.

ISIS-360: about message shows version and other manifest attributes.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/0a7b7a53
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/0a7b7a53
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/0a7b7a53

Branch: refs/heads/dan/ISIS-233-ro
Commit: 0a7b7a53dc37d066a292ea23b22a07ccb260f46b
Parents: 06c95bd
Author: Dan Haywood <da...@apache.org>
Authored: Fri Mar 8 11:39:35 2013 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Mar 8 11:39:35 2013 +0000

----------------------------------------------------------------------
 .../wicket/ui/components/about/AboutPanel.html     |    2 +-
 .../wicket/ui/components/about/AboutPanel.java     |   35 ++-
 .../ui/components/about/AboutPanelFactory.java     |   21 +--
 .../ui/components/about/JarManifestAttributes.java |   50 ++++
 .../ui/components/about/JarManifestListView.java   |   27 ++
 .../ui/components/about/JarManifestModel.java      |  215 +++++++++++++++
 .../ui/components/about/JarManifestPanel.css       |   99 +++++++
 .../ui/components/about/JarManifestPanel.html      |   51 ++++
 .../ui/components/about/JarManifestPanel.java      |   64 +++++
 .../wicket/ui/components/about/div-toggle.js       |    7 +
 .../viewer/wicket/ui/errors/ExceptionModel.java    |    1 -
 .../wicket/ui/errors/ExceptionStackTracePanel.java |    1 -
 .../org/apache/isis/core/commons/lang/IoUtils.java |    9 +-
 .../viewer-webapp/pom.xml                          |  107 +++++++-
 .../src/main/java/app/QuickStartApplication.java   |   38 +++-
 15 files changed, 689 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.html
index 3e27d27..b4dc1ec 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.html
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.html
@@ -19,6 +19,6 @@
 -->
 <wicket:panel>
 	<div class="aboutPanel aboutComponentType">
-		<span wicket:id="message" id="message">About message goes here</span>
+        <div wicket:id="manifestAttributes"/>
 	</div>
 </wicket:panel>

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.java
index 429f32e..8522849 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanel.java
@@ -19,15 +19,15 @@
 
 package org.apache.isis.viewer.wicket.ui.components.about;
 
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-
-import org.apache.wicket.markup.html.basic.MultiLineLabel;
+import java.io.InputStream;
 
 import org.apache.isis.viewer.wicket.model.models.AboutModel;
 import org.apache.isis.viewer.wicket.ui.pages.home.HomePage;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+
 /**
  * {@link PanelAbstract Panel} displaying welcome message (as used on
  * {@link HomePage}).
@@ -36,16 +36,31 @@ public class AboutPanel extends PanelAbstract<AboutModel> {
 
     private static final long serialVersionUID = 1L;
 
-    private static final String ID_MESSAGE = "message";
+    private static final String ID_MANIFEST_ATTRIBUTES = "manifestAttributes";
 
     @Inject
     @Named("aboutMessage")
     private String aboutMessage;
-
-    public AboutPanel(final String id, final AboutModel model) {
-        super(id, model);
-        getModel().setObject(aboutMessage);
-        add(new MultiLineLabel(ID_MESSAGE, model.getObject()));
+    
+    /**
+     * We take care to read this only once.
+     */
+    @Inject
+    @Named("metaInfManifest")
+    private InputStream metaInfManifestIs;
+    
+    private JarManifestModel jarManifestModel;
+    
+    public AboutPanel(final String id) {
+        super(id);
+        //getModel().setObject(aboutMessage);
+        
+        if(jarManifestModel == null) {
+            jarManifestModel = new JarManifestModel(aboutMessage, metaInfManifestIs);
+        }
+        
+        //add(new MultiLineLabel(ID_MESSAGE, jarManifestModel.getAboutMessage()).setEscapeModelStrings(false));
+        add(new JarManifestPanel(ID_MANIFEST_ATTRIBUTES, jarManifestModel));
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanelFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanelFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanelFactory.java
index 3650922..e86aa69 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanelFactory.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/AboutPanelFactory.java
@@ -19,17 +19,11 @@
 
 package org.apache.isis.viewer.wicket.ui.components.about;
 
-import java.nio.charset.Charset;
-
-import com.google.common.io.Resources;
-
-import org.apache.wicket.Component;
-import org.apache.wicket.model.IModel;
-
-import org.apache.isis.viewer.wicket.model.models.AboutModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.wicket.Component;
+import org.apache.wicket.model.IModel;
 
 /**
  * {@link ComponentFactory} for {@link AboutPanel}.
@@ -37,7 +31,6 @@ import org.apache.isis.viewer.wicket.ui.ComponentType;
 public class AboutPanelFactory extends ComponentFactoryAbstract {
 
     private static final long serialVersionUID = 1L;
-    private static final String META_INF_POM_PROPERTIES = "/META-INF/maven/org.apache.isis.viewer/wicket-viewer/pom.properties";
 
     public AboutPanelFactory() {
         super(ComponentType.ABOUT);
@@ -50,15 +43,7 @@ public class AboutPanelFactory extends ComponentFactoryAbstract {
 
     @Override
     public Component createComponent(final String id, final IModel<?> model) {
-        return new AboutPanel(id, new AboutModel(versionFromManifest()));
-    }
-
-    private static String versionFromManifest() {
-        try {
-            return Resources.toString(Resources.getResource(META_INF_POM_PROPERTIES), Charset.defaultCharset());
-        } catch (final Exception ex) {
-            return "UNKNOWN";
-        }
+        return new AboutPanel(id);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestAttributes.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestAttributes.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestAttributes.java
new file mode 100644
index 0000000..d2fe930
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestAttributes.java
@@ -0,0 +1,50 @@
+package org.apache.isis.viewer.wicket.ui.components.about;
+
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Map.Entry;
+
+public class JarManifestAttributes implements Serializable {
+    
+    private static final long serialVersionUID = 1L;
+
+    public static JarManifestAttributes jarName(String jarName) {
+        return new JarManifestAttributes(JarManifestAttributes.Type.JAR_NAME, jarName);
+    }
+
+    public static JarManifestAttributes jarUrl(URL jarUrl) {
+        return new JarManifestAttributes(JarManifestAttributes.Type.JAR_URL, jarUrl != null? jarUrl.toExternalForm(): "");
+    }
+
+    public static JarManifestAttributes attribute(Entry<Object,Object> entry) {
+        StringBuilder buf = new StringBuilder();
+        buf .append("    ")
+            .append(entry.getKey())
+            .append(": ")
+            .append(entry.getValue())
+            .append("\n")
+            ;
+        return new JarManifestAttributes(JarManifestAttributes.Type.MANIFEST_ATTRIBUTE, buf.toString());
+    }
+
+    enum Type {
+        JAR_NAME,
+        JAR_URL,
+        MANIFEST_ATTRIBUTE
+    }
+    
+    private final Type type;
+    private final String line;
+    
+    public JarManifestAttributes(Type type, String line) {
+        this.type = type;
+        this.line = line;
+    }
+    public JarManifestAttributes.Type getType() {
+        return type;
+    }
+    public String getLine() {
+        return line;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestListView.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestListView.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestListView.java
new file mode 100644
index 0000000..5d9f32e
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestListView.java
@@ -0,0 +1,27 @@
+package org.apache.isis.viewer.wicket.ui.components.about;
+
+import java.util.List;
+
+import org.apache.wicket.behavior.AttributeAppender;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.list.ListItem;
+import org.apache.wicket.markup.html.list.ListView;
+
+public final class JarManifestListView extends ListView<JarManifestAttributes> {
+    
+    private static final long serialVersionUID = 1L;
+    private final String idLine;
+
+    public JarManifestListView(String id, String idLine, List<? extends JarManifestAttributes> list) {
+        super(id, list);
+        this.idLine = idLine;
+    }
+
+    @Override
+    protected void populateItem(ListItem<JarManifestAttributes> item) {
+        final JarManifestAttributes detail = item.getModelObject();
+        Label label = new Label(idLine, detail.getLine());
+        item.add(new AttributeAppender("class", detail.getType().name().toLowerCase()));
+        item.add(label);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestModel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestModel.java
new file mode 100644
index 0000000..8ca2086
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestModel.java
@@ -0,0 +1,215 @@
+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 org.apache.isis.core.commons.lang.IoUtils;
+import org.apache.isis.viewer.wicket.model.models.ModelAbstract;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+
+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 {
+            IoUtils.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 {
+                IoUtils.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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.css
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.css b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.css
new file mode 100644
index 0000000..bf91f39
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.css
@@ -0,0 +1,99 @@
+/*
+ *  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.
+ */
+
+ .jarManifestPanel .aboutInfo {
+    margin-left: 50px;
+    margin-right: 50px;
+    padding-top: 50px;
+}
+
+
+.jarManifestPanel .aboutMessage {
+    background:#FFFFFF;
+    border-radius:4px;
+    -moz-border-radius:4px;
+    -webkit-border-radius:4px;
+    padding: 15px;
+    display: block;
+    text-align:center;
+    font-size:1.2em;
+}
+
+ .jarManifestPanel .manifestAttributes {
+    margin-top: 30px; 
+}
+
+.jarManifestPanel .heading {
+    border-radius:4px;
+    -moz-border-radius:4px;
+    -webkit-border-radius:4px;
+    background-color:#F0EFEA;
+
+    display:block;
+    font-style:normal !important;
+
+    padding:1px 6px 1px 6px;
+}
+
+.jarManifestPanel .heading span {
+    display:block;
+    font-style:normal !important;
+    padding:3px 3px 3px 3px;
+    font-size: 0.8em;
+    text-transform:uppercase;
+    font-weight:bold;
+}
+
+.jarManifestPanel .heading:hover {
+    background-color:#FFFFFF;
+    cursor: pointer;
+}
+
+.jarManifestPanel h3 {
+    font-size: larger;
+}
+
+.jarManifestPanel .manifestAttributesList .caused_by_label {
+    margin-top: 30px;
+    font-style:normal !important;
+    font-size: 0.8em;
+    text-transform:uppercase;
+    font-weight:bold;
+    color: #46423C;
+}
+
+.jarManifestPanel .manifestAttributesList .jar_name {
+    margin-top: 15px;
+    font-size: 1.2em;
+    font-weight:bold;
+    color: #46423C;
+}
+
+.jarManifestPanel .manifestAttributesList .jar_url {
+    margin-top: 10px;
+    margin-bottom: 10px;
+    font-style: italic;
+    font-size: 1.0em;
+    color: #00477F;
+}
+
+.jarManifestPanel .manifestAttributesList .manifest_attribute{
+    margin-left: 30px;
+}
+ 
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.html
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.html b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.html
new file mode 100644
index 0000000..40d5047
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.html
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html>
+<!--
+  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.
+-->
+<html xmlns="http://www.w3.org/1999/xhtml"  
+      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd"  
+      xml:lang="en"  
+      lang="en">
+    <head>
+        <wicket:link>
+            <link href="JarManifestPanel.css" rel="stylesheet" type="text/css"/>
+        </wicket:link>
+    </head>
+    <body>
+        <wicket:panel>
+            <div class="jarManifestPanel">
+                <div class="aboutInfo clear">
+                    <span wicket:id="aboutMessage" class="aboutMessage">[about message text]</span>
+                    <div class="manifestAttributes" wicket:id="manifestAttributes">
+                        <div class="heading"><span>Jar manifest attributes</span></div>
+                        <div class="content">
+                            <div class="manifestAttributesList">
+                                <ul>
+                                    <li wicket:id="manifestAttribute">
+                                        <span wicket:id="manifestAttributeLine">[manifest attribute line]</span>
+                                    </li>
+                                </ul>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </wicket:panel>
+    </body>
+</html>

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.java
new file mode 100644
index 0000000..e609a08
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/JarManifestPanel.java
@@ -0,0 +1,64 @@
+/*
+ *  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 org.apache.isis.viewer.wicket.ui.panels.PanelUtil;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptReferenceHeaderItem;
+import org.apache.wicket.markup.html.WebMarkupContainer;
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.markup.html.panel.Panel;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
+
+public class JarManifestPanel extends Panel {
+
+    private static final long serialVersionUID = 1L;
+
+    private static final String ID_ABOUT_MESSAGE = "aboutMessage";
+
+    private static final String ID_MANIFEST_ATTRIBUTES = "manifestAttributes";
+
+    private static final String ID_MANIFEST_ATTRIBUTE = "manifestAttribute";
+    private static final String ID_LINE = "manifestAttributeLine";
+
+    private static final JavaScriptResourceReference DIV_TOGGLE_JS = new JavaScriptResourceReference(JarManifestPanel.class, "div-toggle.js");
+
+    public JarManifestPanel(String id, JarManifestModel manifestModel) {
+        super(id, manifestModel);
+        
+        add(new Label(ID_ABOUT_MESSAGE, manifestModel.getAboutMessage()).setEscapeModelStrings(false));
+
+        MarkupContainer container = new WebMarkupContainer(ID_MANIFEST_ATTRIBUTES) {
+            private static final long serialVersionUID = 1L;
+            @Override
+            public void renderHead(IHeaderResponse response) {
+                response.render(JavaScriptReferenceHeaderItem.forReference(DIV_TOGGLE_JS));
+            }
+        };
+        container.add(new JarManifestListView(ID_MANIFEST_ATTRIBUTE, JarManifestPanel.ID_LINE, manifestModel.getDetail()));
+        add(container);
+    }
+
+    public void renderHead(final IHeaderResponse response) {
+        PanelUtil.renderHead(response, this.getClass());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/div-toggle.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/div-toggle.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/div-toggle.js
new file mode 100644
index 0000000..b8ae05b
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/about/div-toggle.js
@@ -0,0 +1,7 @@
+jQuery(document).ready(function() {
+  jQuery(".jarManifestPanel .content").hide();
+  jQuery(".jarManifestPanel .heading").click(function()
+  {
+    jQuery(this).next(".jarManifestPanel .content").slideToggle(500);
+  });
+});

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
index c587834..9abee32 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionModel.java
@@ -52,7 +52,6 @@ public class ExceptionModel extends ModelAbstract<Exception> {
         return mainMessage;
     }
     
-    
     public List<StackTraceDetail> getStackTrace() {
         return asStackTrace(exception);
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
index 9409951..a76fefe 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/errors/ExceptionStackTracePanel.java
@@ -35,7 +35,6 @@ public class ExceptionStackTracePanel extends Panel {
     private static final String ID_MAIN_MESSAGE = "mainMessage";
 
     private static final String ID_EXCEPTION_DETAIL = "exceptionDetail";
-    private static final String ID_EXCEPTION_MESSAGE = "exceptionMessage";
 
     private static final String ID_STACK_TRACE_ELEMENT = "stackTraceElement";
     private static final String ID_LINE = "stackTraceElementLine";

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/IoUtils.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/IoUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/IoUtils.java
index 67586a8..29e56ef 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/IoUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/commons/lang/IoUtils.java
@@ -74,11 +74,12 @@ public final class IoUtils {
         return in;
     }
 
-    public static void closeSafely(final Closeable reader) {
-        if (reader != null) {
+    public static void closeSafely(final Closeable closeable) {
+        if (closeable != null) {
             try {
-                reader.close();
-            } catch (final IOException ignore) {
+                closeable.close();
+            } catch (final Exception ignore) {
+                // ignore
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/example/application/quickstart_wicket_restful_jdo/viewer-webapp/pom.xml
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/pom.xml b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/pom.xml
index df2db7c..d53afce 100644
--- a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/pom.xml
+++ b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/pom.xml
@@ -75,7 +75,87 @@
                 </configuration>
             </plugin>
 
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>1.5</version>
+                  <executions>
+                    <execution>
+                      <phase>validate</phase>
+                      <goals>
+                        <goal>maven-version</goal>
+                      </goals>
+                    </execution>
+                  </executions>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-war-plugin</artifactId>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>false</addClasspath>
+                        </manifest>                            
+                        <manifestEntries>
+                            <Build-Time>${maven.build.timestamp}</Build-Time>
+                            <Build-Host>${agent.name}</Build-Host>
+                            <Build-User>${user.name}</Build-User>
+                            <Build-Maven>Maven ${maven.version}</Build-Maven>
+                            <Build-Java>${java.version}</Build-Java>
+                            <Build-OS>${os.name}</Build-OS>
+                            <Build-Label>${project.version}</Build-Label>
+                        </manifestEntries>
+                    </archive>
+                </configuration>
+                <!-- 
+                <executions>
+                    <execution>
+                        <id>default-war</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>war</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                 -->
+            </plugin>
+
         </plugins>
+        <pluginManagement>
+            <plugins>
+                <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
+                <plugin>
+                    <groupId>org.eclipse.m2e</groupId>
+                    <artifactId>lifecycle-mapping</artifactId>
+                    <version>1.0.0</version>
+                    <configuration>
+                        <lifecycleMappingMetadata>
+                            <pluginExecutions>
+                                <pluginExecution>
+                                    <pluginExecutionFilter>
+                                        <groupId>
+                                            org.codehaus.mojo
+                                        </groupId>
+                                        <artifactId>
+                                            build-helper-maven-plugin
+                                        </artifactId>
+                                        <versionRange>
+                                            [1.5,)
+                                        </versionRange>
+                                        <goals>
+                                            <goal>maven-version</goal>
+                                        </goals>
+                                    </pluginExecutionFilter>
+                                    <action>
+                                        <ignore></ignore>
+                                    </action>
+                                </pluginExecution>
+                            </pluginExecutions>
+                        </lifecycleMappingMetadata>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
     </build>
 
     <dependencies>
@@ -84,18 +164,42 @@
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>quickstart_wicket_restful_jdo-dom</artifactId>
+            <exclusions>
+                <exclusion>
+                    <!-- so don't pick up transitive dependency to asm 4.0.0, which is
+                         incompatible with asm 3.3.1 as used by guice -->
+                    <groupId>org.datanucleus</groupId>
+                    <artifactId>datanucleus-enhancer</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>quickstart_wicket_restful_jdo-fixture</artifactId>
+            <exclusions>
+                <exclusion>
+                    <!-- so don't pick up transitive dependency to asm 4.0.0, which is
+                         incompatible with asm 3.3.1 as used by guice -->
+                    <groupId>org.datanucleus</groupId>
+                    <artifactId>datanucleus-enhancer</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
+
         <!-- objectstore/domain service/repository implementations (brings in dependency to objectstore-jdo)-->
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>quickstart_wicket_restful_jdo-objstore-jdo</artifactId>
+            <exclusions>
+                <exclusion>
+                    <!-- so don't pick up transitive dependency to asm 4.0.0, which is
+                         incompatible with asm 3.3.1 as used by guice -->
+                    <groupId>org.datanucleus</groupId>
+                    <artifactId>datanucleus-enhancer</artifactId>
+                </exclusion>
+            </exclusions>
         </dependency>
         
-        
         <!-- other isis components -->
         <dependency>
             <groupId>org.apache.isis.viewer</groupId>
@@ -165,6 +269,7 @@
           <artifactId>log4jdbc-remix</artifactId>
         </dependency>
 
+
         <!-- 3rd party dependency -->
         <!-- 
         GMAP3: uncomment to use https://github.com/danhaywood/isis-wicket-gmap3

http://git-wip-us.apache.org/repos/asf/isis/blob/0a7b7a53/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/java/app/QuickStartApplication.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/java/app/QuickStartApplication.java b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/java/app/QuickStartApplication.java
index ef8e582..a5ea693 100644
--- a/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/java/app/QuickStartApplication.java
+++ b/example/application/quickstart_wicket_restful_jdo/viewer-webapp/src/main/java/app/QuickStartApplication.java
@@ -19,18 +19,33 @@
 package app;
 
 import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
 import java.nio.charset.Charset;
+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 javax.servlet.ServletContext;
+
+import org.apache.commons.collections.EnumerationUtils;
 import org.apache.isis.viewer.wicket.ui.app.registry.ComponentFactoryRegistrar;
 import org.apache.isis.viewer.wicket.viewer.IsisWicketApplication;
 
 import com.google.common.base.Joiner;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
 import com.google.common.io.Resources;
 import com.google.inject.AbstractModule;
 import com.google.inject.Module;
 import com.google.inject.name.Names;
 import com.google.inject.util.Modules;
+import com.google.inject.util.Providers;
 
 
 /**
@@ -67,14 +82,33 @@ public class QuickStartApplication extends IsisWicketApplication {
                 bind(String.class).annotatedWith(Names.named("applicationCss")).toInstance("css/application.css");
                 bind(String.class).annotatedWith(Names.named("applicationJs")).toInstance("scripts/application.js");
                 bind(String.class).annotatedWith(Names.named("welcomeMessage")).toInstance(readLines("welcome.html"));
-                bind(String.class).annotatedWith(Names.named("aboutMessage")).toInstance("QuickStart v1.0.0");
+                bind(String.class).annotatedWith(Names.named("aboutMessage")).toInstance("QuickStart");
+                bind(InputStream.class).annotatedWith(Names.named("metaInfManifest")).toProvider(Providers.of(getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF")));
             }
-
         };
 
         return Modules.override(isisDefaults).with(quickstartOverrides);
     }
 
+    public static class Archive {
+        private final String name;
+        private final String url;
+        
+        public Archive(String name, String url) {
+            this.name = name;
+            this.url = url;
+        }
+        
+        public String getName() {
+            return name;
+        }
+        public String getUrl() {
+            return url;
+        }
+        
+    }
+
+    
     private static String readLines(final String resourceName) {
         try {
             List<String> readLines = Resources.readLines(Resources.getResource(QuickStartApplication.class, resourceName), Charset.defaultCharset());