diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java
index e3c750826d2dff1b2ebec83a66576c61b73f40f2..28402861dffe2a36997e9691752b59b0eafa5f85 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java
@@ -1,7 +1,7 @@
 /*
  * Autopsy Forensic Browser
  *
- * Copyright 2011-2016 Basis Technology Corp.
+ * Copyright 2011-2017 Basis Technology Corp.
  * Contact: carrier <at> sleuthkit <dot> org
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,11 +22,11 @@
 import java.beans.PropertyChangeListener;
 import java.util.ArrayList;
 import java.util.List;
-import org.openide.nodes.Children;
 import java.util.Map;
 import java.util.logging.Level;
 import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
+import org.openide.nodes.Children;
 import org.openide.nodes.Sheet;
 import org.openide.util.NbBundle;
 import org.sleuthkit.autopsy.casemodule.Case;
@@ -47,25 +47,23 @@
  */
 public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends AbstractContentNode<T> {
 
-    private static final Logger LOGGER = Logger.getLogger(AbstractAbstractFileNode.class.getName());
+    private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName());
+
+    @NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description")
+    private static final String NO_DESCR = Bundle.AbstractAbstractFileNode_addFileProperty_desc();
 
     /**
-     * @param <T> type of the AbstractFile data to encapsulate
-     * @param abstractFile file to encapsulate
+     * @param abstractFile file to wrap
      */
     AbstractAbstractFileNode(T abstractFile) {
         super(abstractFile);
-        String name = abstractFile.getName();
-        int dotIndex = name.lastIndexOf(".");
-        if (dotIndex > 0) {
-            String ext = name.substring(dotIndex).toLowerCase();
-
+        String ext = abstractFile.getNameExtension();
+        if (StringUtils.isNotBlank(ext)) {
+            ext = "." + ext;
             // If this is an archive file we will listen for ingest events
             // that will notify us when new content has been identified.
-            for (String s : FileTypeExtensions.getArchiveExtensions()) {
-                if (ext.equals(s)) {
-                    IngestManager.getInstance().addIngestModuleEventListener(pcl);
-                }
+            if (FileTypeExtensions.getArchiveExtensions().contains(ext)) {
+                IngestManager.getInstance().addIngestModuleEventListener(pcl);
             }
         }
         // Listen for case events so that we can detect when case is closed
@@ -127,144 +125,149 @@ private void updateSheet() {
         this.setSheet(createSheet());
     }
 
-    // Note: this order matters for the search result, changed it if the order of property headers on the "KeywordSearchNode"changed
     public static enum AbstractFilePropertyType {
 
         NAME {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.nameColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.nameColLbl");
+            }
+        },
+        EXTENSION {
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.extensionColLbl");
+            }
+        },
         LOCATION {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.locationColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.locationColLbl");
+            }
+        },
         MOD_TIME {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.modifiedTimeColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.modifiedTimeColLbl");
+            }
+        },
         CHANGED_TIME {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.changeTimeColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.changeTimeColLbl");
+            }
+        },
         ACCESS_TIME {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.accessTimeColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.accessTimeColLbl");
+            }
+        },
         CREATED_TIME {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.createdTimeColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.createdTimeColLbl");
+            }
+        },
         SIZE {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.sizeColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.sizeColLbl");
+            }
+        },
         FLAGS_DIR {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.flagsDirColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.flagsDirColLbl");
+            }
+        },
         FLAGS_META {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.flagsMetaColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.flagsMetaColLbl");
+            }
+        },
         MODE {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.modeColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.modeColLbl");
+            }
+        },
         USER_ID {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.useridColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.useridColLbl");
+            }
+        },
         GROUP_ID {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.groupidColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.groupidColLbl");
+            }
+        },
         META_ADDR {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.metaAddrColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.metaAddrColLbl");
+            }
+        },
         ATTR_ADDR {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.attrAddrColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.attrAddrColLbl");
+            }
+        },
         TYPE_DIR {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.typeDirColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.typeDirColLbl");
+            }
+        },
         TYPE_META {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.typeMetaColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.typeMetaColLbl");
+            }
+        },
         KNOWN {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.knownColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.knownColLbl");
+            }
+        },
         HASHSETS {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.inHashsetsColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.inHashsetsColLbl");
+            }
+        },
         MD5HASH {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.md5HashColLbl");
-                    }
-                },
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.md5HashColLbl");
+            }
+        },
         ObjectID {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.objectId");
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.objectId");
 
-                    }
-                },
+            }
+        },
         MIMETYPE {
-                    @Override
-                    public String toString() {
-                        return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.mimeType");
+            @Override
+            public String toString() {
+                return NbBundle.getMessage(this.getClass(), "AbstractAbstractFileNode.mimeType");
 
-                    }
-                },
+            }
+        },
     }
 
     /**
      * Fill map with AbstractFile properties
      *
-     * @param map map with preserved ordering, where property names/values are
-     * put
+     * @param map     map with preserved ordering, where property names/values
+     *                are put
      * @param content to extract properties from
      */
     public static void fillPropertyMap(Map<String, Object> map, AbstractFile content) {
@@ -273,10 +276,10 @@ public static void fillPropertyMap(Map<String, Object> map, AbstractFile content
         try {
             path = content.getUniquePath();
         } catch (TskCoreException ex) {
-            LOGGER.log(Level.SEVERE, "Except while calling Content.getUniquePath() on {0}", content); //NON-NLS
+            logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on {0}", content); //NON-NLS
         }
 
-        map.put(AbstractFilePropertyType.NAME.toString(), AbstractAbstractFileNode.getContentDisplayName(content));
+        map.put(AbstractFilePropertyType.NAME.toString(), getContentDisplayName(content));
         map.put(AbstractFilePropertyType.LOCATION.toString(), path);
         map.put(AbstractFilePropertyType.MOD_TIME.toString(), ContentUtils.getStringTime(content.getMtime(), content));
         map.put(AbstractFilePropertyType.CHANGED_TIME.toString(), ContentUtils.getStringTime(content.getCtime(), content));
@@ -289,32 +292,34 @@ public static void fillPropertyMap(Map<String, Object> map, AbstractFile content
         map.put(AbstractFilePropertyType.USER_ID.toString(), content.getUid());
         map.put(AbstractFilePropertyType.GROUP_ID.toString(), content.getGid());
         map.put(AbstractFilePropertyType.META_ADDR.toString(), content.getMetaAddr());
-        map.put(AbstractFilePropertyType.ATTR_ADDR.toString(), Long.toString(content.getAttrType().getValue()) + "-" + content.getAttributeId());
+        map.put(AbstractFilePropertyType.ATTR_ADDR.toString(), content.getAttrType().getValue() + "-" + content.getAttributeId());
         map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel());
         map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString());
         map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName());
         map.put(AbstractFilePropertyType.HASHSETS.toString(), getHashSetHitsForFile(content));
-        map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
+        map.put(AbstractFilePropertyType.MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash()));
         map.put(AbstractFilePropertyType.ObjectID.toString(), content.getId());
-        map.put(AbstractFilePropertyType.MIMETYPE.toString(), content.getMIMEType() == null ? "" : content.getMIMEType());
+        map.put(AbstractFilePropertyType.MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType()));
+        map.put(AbstractFilePropertyType.EXTENSION.toString(), content.getNameExtension());
     }
 
     /**
      * Used by subclasses of AbstractAbstractFileNode to add the tags property
      * to their sheets.
-     * @param ss the modifiable Sheet.Set returned by Sheet.get(Sheet.PROPERTIES)
+     *
+     * @param ss the modifiable Sheet.Set returned by
+     *           Sheet.get(Sheet.PROPERTIES)
      */
     protected void addTagProperty(Sheet.Set ss) {
-        final String NO_DESCR = NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.desc");
         List<ContentTag> tags;
         try {
             tags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content);
         } catch (TskCoreException ex) {
             tags = new ArrayList<>();
-            LOGGER.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex);
+            logger.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex);
         }
         ss.put(new NodeProperty<>("Tags", NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.addFileProperty.tags.displayName"),
-                NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
+                NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).distinct().collect(Collectors.joining(", "))));
     }
 
     static String getContentDisplayName(AbstractFile file) {
@@ -330,12 +335,11 @@ static String getContentDisplayName(AbstractFile file) {
         }
     }
 
-    @SuppressWarnings("deprecation")
     private static String getHashSetHitsForFile(AbstractFile content) {
         try {
             return StringUtils.join(content.getHashSetNames(), ", ");
         } catch (TskCoreException tskCoreException) {
-            LOGGER.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS
+            logger.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS
             return "";
         }
     }
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties
index 964b2df827f4010d4c78f2c5ddc905408e06926e..13b2cd63bf5f6b748dda764142480d35d1d62ea4 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties
@@ -18,6 +18,7 @@ AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)
 AbstractAbstractFileNode.knownColLbl=Known
 AbstractAbstractFileNode.inHashsetsColLbl=In Hashsets
 AbstractAbstractFileNode.md5HashColLbl=MD5 Hash
+AbstractAbstractFileNode.extensionColLbl=Extension
 AbstractAbstractFileNode.mimeType = MIME Type
 AbstractContentChildren.CreateTSKNodeVisitor.exception.noNodeMsg=No Node defined for the given SleuthkitItem
 AbstractContentChildren.createAutopsyNodeVisitor.exception.noNodeMsg=No Node defined for the given DisplayableItem
@@ -229,7 +230,6 @@ DeleteReportAction.actionDisplayName.multipleReports=Delete Reports
 DeleteReportAction.actionPerformed.showConfirmDialog.title=Confirm Deletion
 DeleteReportAction.actionPerformed.showConfirmDialog.single.msg=Do you want to delete 1 report from the case?
 DeleteReportAction.actionPerformed.showConfirmDialog.multiple.msg=Do you want to delete {0} reports from the case?
-AbstractAbstractFileNode.addFileProperty.desc=no description
 AbstractAbstractFileNode.addFileProperty.tags.name=Tags
 AbstractAbstractFileNode.addFileProperty.tags.displayName=Tags
 BlackboardArtifactNode.createSheet.tags.name=Tags
@@ -244,4 +244,4 @@ FileTypeExtensionFilters.autDocHtmlFilter.text=HTML
 FileTypeExtensionFilters.autDocOfficeFilter.text=Office
 FileTypeExtensionFilters.autoDocPdfFilter.text=PDF
 FileTypeExtensionFilters.autDocTxtFilter.text=Plain Text
-FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text
\ No newline at end of file
+FileTypeExtensionFilters.autDocRtfFilter.text=Rich Text