Stephen Abrams avatar Stephen Abrams committed 614875f

Initial fix for issue #115, rationalization of Source class hierarchy, removing ZipFileSource and ZipDirectorySource. All manual tests OK but two unit tests still fail

Comments (0)

Files changed (56)

config/properties/module/display/displayer/org/jhove2/core/source/DirectorySource_displayer.properties

 # A property is not displayed if its value is not consistent with the directive.
 # Negative means ...,-2,-1; NonNegative means 0,1,2...
 # Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
-http\://jhove2.org/terms/property/org/jhove2/core/source/DirectorySource/Path	Always
+http\://jhove2.org/terms/property/org/jhove2/core/source/DirectorySource/SourceName	Always

config/properties/module/display/displayer/org/jhove2/core/source/FileSource_displayer.properties

 # A property is not displayed if its value is not consistent with the directive.
 # Negative means ...,-2,-1; NonNegative means 0,1,2...
 # Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
-http\://jhove2.org/terms/property/org/jhove2/core/source/FileSource/LastModified	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/FileSource/Path	Always
 http\://jhove2.org/terms/property/org/jhove2/core/source/FileSource/Size	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/FileSource/isHidden	IfTrue
-http\://jhove2.org/terms/property/org/jhove2/core/source/FileSource/isSpecial	IfTrue
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSource/SourceName	Always

config/properties/module/display/displayer/org/jhove2/core/source/FileSystemProperties_displayer.properties

+# displayer.properties
+# The visibility directives control the display of the properties identified by URI
+# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
+# IfNonZero, IfPositive, IfTrue, IfZero, Never
+# A property is not displayed if its value is not consistent with the directive.
+# Negative means ...,-2,-1; NonNegative means 0,1,2...
+# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemProperties/isExtant	IfFalse
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemProperties/isHidden	IfTrue
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemProperties/isReadable	IfFalse
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemProperties/isSpecial	IfTrue
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemProperties/LastModified	Always
+http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemProperties/Path	Always

config/properties/module/display/displayer/org/jhove2/core/source/FileSystemSource_displayer.properties

-# displayer.properties
-# The visibility directives control the display of the properties identified by URI
-# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
-# IfNonZero, IfPositive, IfTrue, IfZero, Never
-# A property is not displayed if its value is not consistent with the directive.
-# Negative means ...,-2,-1; NonNegative means 0,1,2...
-# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
-http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemSource/isExtant   IfFalse
-http\://jhove2.org/terms/property/org/jhove2/core/source/FileSystemSource/isReadable IfFalse

config/properties/module/display/displayer/org/jhove2/core/source/MeasurableSource_displayer.properties

+# displayer.properties
+# The visibility directives control the display of the properties identified by URI
+# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
+# IfNonZero, IfPositive, IfTrue, IfZero, Never
+# A property is not displayed if its value is not consistent with the directive.
+# Negative means ...,-2,-1; NonNegative means 0,1,2...
+# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
+http\://jhove2.org/terms/property/org/jhove2/core/source/MeasurableSource/EndingOffset	Always
+http\://jhove2.org/terms/property/org/jhove2/core/source/MeasurableSource/Size			Always
+http\://jhove2.org/terms/property/org/jhove2/core/source/MeasurableSource/StartingOffset	Always

config/properties/module/display/displayer/org/jhove2/core/source/MensurableSource_displayer.properties

-# displayer.properties
-# The visibility directives control the display of the properties identified by URI
-# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
-# IfNonZero, IfPositive, IfTrue, IfZero, Never
-# A property is not displayed if its value is not consistent with the directive.
-# Negative means ...,-2,-1; NonNegative means 0,1,2...
-# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
-http\://jhove2.org/terms/property/org/jhove2/core/source/MensurableSource/EndingOffset	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/MensurableSource/Size			Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/MensurableSource/StartingOffset	Always

config/properties/module/display/displayer/org/jhove2/core/source/Source_displayer.properties

 # Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
 http\://jhove2.org/terms/message/org/jhove2/core/source/Source/Messages	Always
 http\://jhove2.org/terms/property/org/jhove2/core/source/Source/ChildSources	Always
+http\://jhove2.org/terms/property/org/jhove2/core/source/Source/ExtraProperties	Always
+http\://jhove2.org/terms/property/org/jhove2/core/source/Source/FileSystemProperties	Always
 http\://jhove2.org/terms/property/org/jhove2/core/source/Source/hasChildSources	Always
 http\://jhove2.org/terms/property/org/jhove2/core/source/Source/isAggregate	Always
 http\://jhove2.org/terms/property/org/jhove2/core/source/Source/Modules	Always

config/properties/module/display/displayer/org/jhove2/core/source/ZIpDirectorySource_displayer.properties

-# _displayer.properties
-# The visibility directives control the display of the properties identified by URI
-# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
-#                        IfNonZero, IfPositive, IfTrue, IfZero, Never
-# A property is not displayed if its value is not consistent with the directive.
-# Negative means ...,-2,-1; NonNegative means 0,1,2...
-# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipDirectorySource/Comment	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipDirectorySource/LastModified	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipDirectorySource/Path	Always

config/properties/module/display/displayer/org/jhove2/core/source/ZipFileSource_displayer.properties

-# _displayer.properties
-# The visibility directives control the display of the properties identified by URI
-# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
-#                        IfNonZero, IfPositive, IfTrue, IfZero, Never
-# A property is not displayed if its value is not consistent with the directive.
-# Negative means ...,-2,-1; NonNegative means 0,1,2...
-# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipFileSource/CRC32MessageDigest	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipFileSource/Comment	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipFileSource/LastModified	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipFileSource/Path	Always
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipFileSource/Size	Always

config/properties/module/display/displayer/org/jhove2/module/format/zip/ZipEntryProperties_displayer.properties

+# _displayer.properties
+# The visibility directives control the display of the properties identified by URI
+# The directives can be: Always, IfFalse, IfNegative, IfNonNegative, IfNonPositive,
+#                        IfNonZero, IfPositive, IfTrue, IfZero, Never
+# A property is not displayed if its value is not consistent with the directive.
+# Negative means ...,-2,-1; NonNegative means 0,1,2...
+# Positive means 1,2,3,...; NonPositive means ...,-2,-1,0
+http\://jhove2.org/terms/property/org/jhove2/module/format/zip/ZipEntryProperties/Comment	Always
+http\://jhove2.org/terms/property/org/jhove2/module/format/zip/ZipEntryProperties/CompressedSize	IfNonNegative
+http\://jhove2.org/terms/property/org/jhove2/module/format/zip/ZipEntryProperties/CRC32	Always
+http\://jhove2.org/terms/property/org/jhove2/module/format/zip/ZipEntryProperties/LastModified	Always
+http\://jhove2.org/terms/property/org/jhove2/module/format/zip/ZipEntryProperties/Name	Always

config/properties/module/display/units/org/jhove2/core/source/MeasurableSource_unit.properties

+# Units of measure properties
+# Note: These unit of measure labels are descriptive only; changing the label
+# does NOT change the determination of the underlying property value.
+
+http\://jhove2.org/terms/property/org/jhove2/core/source/MeasurableSource/EndingOffset   byte
+http\://jhove2.org/terms/property/org/jhove2/core/source/MeasurableSource/Size           byte
+http\://jhove2.org/terms/property/org/jhove2/core/source/MeasurableSource/StartingOffset byte

config/properties/module/display/units/org/jhove2/core/source/MensurableSource_unit.properties

-# Units of measure properties
-# Note: These unit of measure labels are descriptive only; changing the label
-# does NOT change the determination of the underlying property value.
-
-http\://jhove2.org/terms/property/org/jhove2/core/source/MensurableSource/EndingOffset   byte
-http\://jhove2.org/terms/property/org/jhove2/core/source/MensurableSource/Size           byte
-http\://jhove2.org/terms/property/org/jhove2/core/source/MensurableSource/StartingOffset byte

config/properties/module/display/units/org/jhove2/core/source/ZipFileSource_unit.properties

-# Units of measure properties
-# Note: These unit of measure labels are descriptive only; changing the label
-# does NOT change the determination of the underlying property value.
-http\://jhove2.org/terms/property/org/jhove2/core/source/ZipFileSource/Size        byte

config/properties/module/display/units/org/jhove2/module/format/zip/ZipEntryProperties_unit.properties

+# Units of measure properties
+# Note: These unit of measure labels are descriptive only; changing the label
+# does NOT change the determination of the underlying property value.
+
+http\://jhove2.org/terms/property/org/jhove2/module/format/zip/ZipEntryProperties/CompressedSize   byte

src/main/java/org/jhove2/core/JHOVE2.java

 import org.jhove2.core.Message.Context;
 import org.jhove2.core.Message.Severity;
 import org.jhove2.core.io.Input;
-import org.jhove2.core.source.FileSystemSource;
+import org.jhove2.core.source.FileSystemProperties;
 import org.jhove2.core.source.NamedSource;
 import org.jhove2.core.source.Source;
 import org.jhove2.core.source.SourceCounter;
 		
             /* Characterize the source unit. */
             boolean tryIt = true;
-            if (source instanceof FileSystemSource) {
-                FileSystemSource fs = (FileSystemSource) source;
-                String name = fs.getSourceName();
-                if (!fs.isExtant()) {
+            /* Check to see if this is a file system source unit, that is, a
+             * physical file or directory on the file system, and if so,
+             * that it exists and is readable.
+             */
+            FileSystemProperties properties = source.getFileSystemProperties();
+            if (properties != null) {
+                String name = ((NamedSource) source).getSourceName();
+                if (!properties.isExtant()) {
                     source = source.addMessage(new Message(Severity.ERROR,
                         Context.PROCESS,
                         "org.jhove2.core.source.FileSystemSource.FileNotFoundMessage",
                         new Object[]{name}, this.getConfigInfo()));
                     tryIt = false;
                 }
-                else if (!fs.isReadable()) {
+                else if (!properties.isReadable()) {
                     source = source.addMessage(new Message(Severity.ERROR,
                         Context.PROCESS,
                         "org.jhove2.core.source.FileSystemSource.FileNotReadableMessage",

src/main/java/org/jhove2/core/io/AbstractInput.java

 	protected File file;
 	
 	/** Temporary file deletion status: true if delete on close. */
-	protected boolean deleteOnClose;
+	protected boolean deleteTempFileOnClose;
 
 	/** InputStream underlying the inputable. */
 	protected InputStream stream;
 	 *            Java {@link java.io.File} underlying the inputable
 	 * @param isTemp
 	 *            Temporary file status: true if temporary
-	 * @param order
+     * @param deleteTempFileOnClose Temporary file deletion flag: if true
+     *                              delete temporary file on close@param order
 	 *            Byte order
 	 * @throws FileNotFoundException
 	 *             File not found
         this.byteOrder = order;   
         Invocation inv = jhove2.getInvocation();
         this.maxBufferSize = inv.getBufferSize();
-	    this.deleteOnClose = inv.getDeleteTempFilesOnClose();
+	    this.deleteTempFileOnClose = inv.getDeleteTempFilesOnClose();
 	    if (!file.isDirectory()) {
 	        this.stream = new BufferedInputStream(new FileInputStream(file),
 	                                              this.maxBufferSize);
 	        this.channel = null;
 	    }
 	    if (this.file != null) {
-	        if (this.isTemp && this.deleteOnClose) {
+	        if (this.isTemp && this.deleteTempFileOnClose) {
 	            this.file.delete();
 	            this.file = null;
 	        }
      * @see org.jhove2.core.io.Input#setDeleteTempOnClose()
      */
 	@Override
-    public void setDeleteTempOnClose(boolean flag) {
-        this.deleteOnClose = flag;
+    public void setDeleteTempFileOnClose(boolean flag) {
+        this.deleteTempFileOnClose = flag;
     }
     
 	/**

src/main/java/org/jhove2/core/io/Input.java

      * @param flag
      *            Delete temporary files flag
      */
-    public void setDeleteTempOnClose(boolean flag);
+    public void setDeleteTempFileOnClose(boolean flag);
 
 	/**
 	 * Set current position, as a byte offset.

src/main/java/org/jhove2/core/io/InputFactory.java

 	 */
 	public static Input getInput(JHOVE2 jhove2, File file, boolean isTemp,
 	                             ByteOrder order)
-	    throws FileNotFoundException, IOException
+	    throws IOException
 	{
 		AbstractInput input = null;
 		if (file != null && file.exists() && file.canRead()) {

src/main/java/org/jhove2/core/source/AbstractSource.java

 import org.jhove2.core.TimerInfo;
 import org.jhove2.core.format.FormatIdentification;
 import org.jhove2.core.io.Input;
-import org.jhove2.core.io.InputFactory;
 import org.jhove2.core.reportable.AbstractReportable;
+import org.jhove2.core.reportable.Reportable;
 import org.jhove2.module.Module;
 import org.jhove2.persist.SourceAccessor;
 
 
 	/** Temporary file deletion flag; if true, delete on close. */
 	protected boolean deleteTempFileOnClose;
+	
+	/** Extra properties.  Extra properties are those not known at the time a
+	 * source unit is instantiated and are not associated with a particular
+	 * {@link org.jhove2.module.format.FormatModule}. */
+	protected List<Reportable> extraProperties;
     
 	/** Source unit backing file. This may be an actual file system
 	 * file or a temporary file created from an {@link java.io.InputStream}.
 	 */
-	protected File file;
+	//protected File file;
+	
+	/** File system properties, if the source is a physical file or directory
+	 * in the file system.
+	 */
+	protected FileSystemProperties fileSystemProperties;
 
 	/** Source unit aggregate flag: true if an aggregate. */
 	protected boolean isAggregate;
 	 */
 	protected AbstractSource() {       
         this.deleteTempFileOnClose   = Invocation.DEFAULT_DELETE_TEMP_FILES_ON_CLOSE;
+        this.extraProperties = new ArrayList<Reportable>();
 		this.isAggregate     = false;
         this.isTemp          = false;
 		this.messages        = new ArrayList<Message>();		
 	}
 
 	/**
-	 * Instantiate a new <code>AbstractSource</code> backed by a file.
+	 * Instantiate a new <code>AbstractSource</code>. 
 	 * @param jhove2 JHOVE2 framework object
-	 * @param file
-	 *            File underlying the source unit
 	 */
-	protected AbstractSource(JHOVE2 jhove2, File file) {
-		this();
-		this.file = file;
-	}
-
-	/**
-	 * Instantiate a new <code>AbstractSource</code> backed by an input stream
-	 * by creating a temporary file. 
-	 * @param jhove2 JHOVE2 framework object
-     * @param stream Input stream backing the source unit
-     * @param name   Source unit name
-	 * @throws IOException
-	 */
-	public AbstractSource(JHOVE2 jhove2, InputStream stream, String name)
-		throws IOException
+	public AbstractSource(JHOVE2 jhove2)
 	{
 		this();
-
-        /* Get format extension from name. */
-        Invocation inv = jhove2.getInvocation();
-		this.file = createTempFile(stream, name, inv.getTempDirectoryFile(),
-		                           inv.getTempPrefix(), inv.getTempSuffix(),
-		                           inv.getBufferSize());
-		this.isTemp = true;
+		
+		/* Set the temporary file deletion flag. */
+		Invocation inv = jhove2.getInvocation();
 		this.deleteTempFileOnClose = inv.getDeleteTempFilesOnClose();
+		
+		/* Create the source accessor. */
+		this.setSourceAccessor(jhove2.getSourceFactory().createSourceAccessor(this));
 	}
 
 	/**
 		return this.sourceAccessor.addChildSource(this, child);
 	}
 
+	   
+    /** Add an extra properties {@link org.jhove2.core.reportable.Reportable}
+     * to be associated with the source unit.  Extra properties are those not
+     * known at the time the source unit is instantiated and which are not
+     * associated with a particular {@link org.jhove2.module.format.FormatModule}.
+     * @param properties Extra properties reportable
+     * @return Source with extra properties added
+     * @throws JHOVE2Exception
+     */
+	@Override
+    public Source addExtraProperties(Reportable properties)
+        throws JHOVE2Exception
+    {
+	    return this.getSourceAccessor().addExtraProperties(this, properties);
+    }
+    
 	/** Add a message to be associated with the source unit.
 	 * @param message Message to be associated with the source unit
 	 * @return Source with Message added
 		}
 		return this.sourceAccessor.getChildSources(this);
 	}
+    
+    /** Get extra properties.  Extra properties are those not known at the
+     * time the source unit is instantiated but which are not associated with
+     * a particular {@link org.jhove2.module.format.FormatModule}.
+     * @return Extra properties
+     * @throws JHOVE2Exception
+     */
+    @Override
+    public List<Reportable> getExtraProperties()
+        throws JHOVE2Exception
+    {
+        return this.extraProperties;
+    }
 
     /**
      * Get {@link java.io.File} backing the source unit.
+     * Sources with an underlying tangible backing file
+     * (e.g. {@link org.jhove2.core.source.FileSource},
+     * {@link org.jhove2.core.source.ByteStreamSource}, and
+     * {@link org.jhove2.core.source.URLSource} should override this method
+     * return the appropriate input. 
      * 
      * @return File backing the source unit
      * @see org.jhove2.core.source.Source#getFile()
      */
     @Override
     public File getFile() {
-        return this.file;
+        return null;
     }
+    
+    /** Get {@link org.jhove2.core.source.FileSystemProperties}.
+     * @return File system properties
+     */
+    @Override
+    public FileSystemProperties getFileSystemProperties() {
+        return this.fileSystemProperties;
+    }
+
 
     /**
      * Get little-endian {@link org.jhove2.core.io.Input} for the source unit
      */
 	@Override
     public Input getInput(JHOVE2 jhove2)
-	    throws FileNotFoundException, IOException
+	    throws IOException
 	{
         return this.getInput(jhove2, ByteOrder.BIG_ENDIAN);
     }
 
 	/**
-	 * Create and get {@link org.jhove2.core.io.Input} for the source unit. Concrete
-	 * classes extending this abstract class must provide an implementation of
-	 * this method if they are are based on parsable input. Classes without
-	 * parsable input (e.g. {@link org.jhove2.core.source.ClumpSource} or
-	 * {@link org.jhove2.core.source.DirectorySource} can let this inherited
-	 * method return null.
+	 * Create and get {@link org.jhove2.core.io.Input} for the source unit.
+	 * Sources with tangible input (e.g. {@link org.jhove2.core.source.FileSource},
+	 * {@link org.jhove2.core.source.ByteStreamSource}, and
+	 * {@link org.jhove2.core.source.URLSource} should override this method
+	 * return the appropriate input.
      * If this method is called explicitly, then the corresponding Input.close()
      * method must be called to avoid a resource leak.
 	 * @param jhove2 JHOVE2 framework object
 	 */
 	@Override
 	public Input getInput(JHOVE2 jhove2, ByteOrder order)
-		throws FileNotFoundException, IOException
+        throws IOException
 	{
-		return InputFactory.getInput(jhove2, this.file, this.isTemp, order);
+		return null;
 	}
 
 	/**
-	 * Get {@link java.io.InputStream} backing the source unit.
+	 * Get {@link java.io.InputStream} backing the source unit.  Sources with
+     * tangible input (e.g. {@link org.jhove2.core.source.FileSource},
+     * {@link org.jhove2.core.source.ByteStreamSource}, and
+     * {@link org.jhove2.core.source.DirectorySource} should override this method
+     * return the appropriate stream.
      * If this method is called explicitly, then the corresponding
      * InputStream.close() method must be called to avoid a resource leak. 
 	 * 
 	 */
 	@Override
 	public InputStream getInputStream()
-	    throws FileNotFoundException, IOException
+	    throws IOException
 	{
-	    InputStream stream = null;
-	    if (this.file != null) {
-            stream = new FileInputStream(this.file);
-	    }
-	    return stream;
+	    return null;
 	}
 
 	/** Get source unit messages.
 	 * @param flag
 	 *            Delete temporary files flag
 	 * @throws JHOVE2Exception 
-	 * @see org.jhove2.core.source.Source#setDeleteTempOnClose(boolean)
+	 * @see org.jhove2.core.source.Source#setDeleteTempFileOnClose(boolean)
 	 */
 	@Override
-	public Source setDeleteTempOnClose(boolean flag)
+	public Source setDeleteTempFileOnClose(boolean flag)
 	    throws JHOVE2Exception
 	{
 		this.deleteTempFileOnClose = flag;
         this.isAggregate = flag;
         return this.getSourceAccessor().persistSource(this);
     }
+    
+    /** Set temporary file flag.
+     * @param flag Temporary file flag; true if the backing file is temporary
+     */
+    @Override
+    public Source setIsTemp(boolean flag)
+        throws JHOVE2Exception
+    {
+        this.isTemp = flag;
+        return this.getSourceAccessor().persistSource(this);
+    }
 
     @Override
     public void setParentSourceId(Long parentSourceId) {
         catch (Exception e){}        
         result = prime * result
                 + ((children == null) ? 0 : children.hashCode());
-        result = prime * result + ((file == null) ? 0 : file.hashCode());
         result = prime * result + ((modules == null) ? 0 : modules.hashCode());
         return result;
     }

src/main/java/org/jhove2/core/source/AbstractSourceFactory.java

 	 */
 	@Override
 	public Source getSource(JHOVE2 jhove2, String name)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	    throws IOException, JHOVE2Exception
 	{
-		Source source = SourceFactoryUtil.getSource(jhove2, name, this);
+		Source source = SourceFactoryUtil.getSource(jhove2, name);
 		source = source.getSourceAccessor().persistSource(source);
 		return source;
 	}
 	 */
 	@Override
 	public Source getSource(JHOVE2 jhove2, File file)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	    throws IOException, JHOVE2Exception
 	{
-		Source source = SourceFactoryUtil.getSource(jhove2, file, this);
+		Source source = SourceFactoryUtil.getSource(jhove2, file);
 		source = source.getSourceAccessor().persistSource(source);
 		return source;
 	}
 	public Source getSource(JHOVE2 jhove2, URL url)
 	    throws IOException, JHOVE2Exception
 	{
-		Source source = SourceFactoryUtil.getSource(jhove2, url, this);
+		Source source = SourceFactoryUtil.getSource(jhove2, url);
 		source = source.getSourceAccessor().persistSource(source);
 		return source;
 	}
 	public Source getSource(JHOVE2 jhove2, ZipFile zip, ZipEntry entry)
 	    throws IOException, JHOVE2Exception
 	{
-		Source source = SourceFactoryUtil.getSource(jhove2, zip, entry, this);
+		Source source = SourceFactoryUtil.getSource(jhove2, zip, entry);
 		source = source.getSourceAccessor().persistSource(source);
 		return source;
 	}
      */
 	@Override
     public Source getSource(JHOVE2 jhove2, String name, String...names)
-        throws FileNotFoundException, IOException, JHOVE2Exception
+        throws IOException, JHOVE2Exception
     {
         Source source = SourceFactoryUtil.getSource(jhove2, this, name, names);
         source = source.getSourceAccessor().persistSource(source);
 	 */
 	@Override
 	public Source getSource(JHOVE2 jhove2, List<String> names)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	    throws IOException, JHOVE2Exception
 	{
-		Source source = SourceFactoryUtil.getSource(jhove2, names, this);
+		Source source = SourceFactoryUtil.getSource(jhove2, names);
 		source = source.getSourceAccessor().persistSource(source);
 		return source;
 	}
     
-    /* Get ByteStream source.
+    /** Get ByteStream source.
      * @param jhove2 JHOVE2 framework object
      * @param parent Parent source unit
      * @param offset Starting offset
     {
         ByteStreamSource source =
             SourceFactoryUtil.getByteStreamSource(jhove2, parent, offset, size,
-                                                  name, this);
+                                                  name);
         source = (ByteStreamSource) source.getSourceAccessor().persistSource(source);
         return source;      
     }
     
-	/** Get Clump source. */
+	/** Get Clump source.
+	 * @param jhove2 JHOVE2 framework object */
 	@Override
-	public ClumpSource getClumpSource() throws JHOVE2Exception
+	public ClumpSource getClumpSource(JHOVE2 jhove2) throws JHOVE2Exception
 	{
-		ClumpSource source = SourceFactoryUtil.getClumpSource(this);
+		ClumpSource source = SourceFactoryUtil.getClumpSource(jhove2);
 		source = (ClumpSource) source.getSourceAccessor().persistSource(source);
 		return source;
 	}
+	
+    /**
+     * Utility method to create empty non-file system DirectorySource
+     * @param jhove2 JHOVE2 framework object
+     * @param name   Directory name 
+     * @return Directory source unit
+     * @throws JHOVE2Exception 
+     * @throws IOException 
+     * @throws FileNotFoundException 
+     */
+	@Override
+    public DirectorySource getDirectorySource(JHOVE2 jhove2, String name)
+        throws IOException, JHOVE2Exception
+    {
+	    DirectorySource source = SourceFactoryUtil.getDirectorySource(jhove2, name);
+	    source = (DirectorySource) source.getSourceAccessor().persistSource(source);
+	    return source;
+    }
 
-	/* Get FileSet source. */
+	/* Get FileSet source.
+	 * @param jhove2 JHOVE2 framework object
+	 */
 	@Override
-	public FileSetSource getFileSetSource() throws JHOVE2Exception {
-		FileSetSource source = SourceFactoryUtil.getFileSetSource(this);
+	public FileSetSource getFileSetSource(JHOVE2 jhove2) throws JHOVE2Exception {
+		FileSetSource source = SourceFactoryUtil.getFileSetSource(jhove2);
 		source = (FileSetSource) source.getSourceAccessor().persistSource(source);
 		return source;
 	}

src/main/java/org/jhove2/core/source/ByteStreamSource.java

     /** Starting offset relative to parent source. */
     protected long endingOffset;
     
+    /** Backing file. */
+    protected File file;
+    
     /** Name, if known. */
     protected String name;
     
      * @param offset Starting offset relative to parent
      * @param size   Size of the byte stream
      * @param name   Byte stream name, if known
-     * @param sourceFactory Source factory
      * @throws IOException 
      * @throws JHOVE2Exception 
      */
     protected ByteStreamSource(JHOVE2 jhove2, Source parent, long offset,
-                               long size, String name, SourceFactory sourceFactory)
+                               long size, String name)
         throws IOException, JHOVE2Exception
     {
-        super();
+        super(jhove2);
         if (parent instanceof ByteStreamSource) {
             this.parentFile = ((ByteStreamSource) parent).getParentFile();
         }
         this.bufferSize    = inv.getBufferSize();
         this.deleteTempFileOnClose = inv.getDeleteTempFilesOnClose();
         
-        /* Make this byte stream a child of its parent. */
-        this.setSourceAccessor(sourceFactory.createSourceAccessor(this));
+        //this.setSourceAccessor(sourceFactory.createSourceAccessor(this));
         /* will update parentSourceId and sourceId fields automatically. */
         parent.addChildSource(this);
      }
      */
     @Override
     public InputStream getInputStream()
-        throws FileNotFoundException, IOException
+        throws IOException
     {
         InputStream stream = null;
         stream = new FileInputStream(this.getFile());

src/main/java/org/jhove2/core/source/ClumpSource.java

  */
 
 package org.jhove2.core.source;
+import org.jhove2.core.JHOVE2;
 import com.sleepycat.persist.model.*;
 /**
  * Clump source unit. A clump is an aggregation of file source units that
 	protected ClumpSource() {
 		super();
 	}
+
+    /**
+     * Instantiate a new <code>ClumpSource</code>.
+     * @param jhove2 JHOVE2 framework object
+     */
+    protected ClumpSource(JHOVE2 jhove2) {
+        super(jhove2);
+    }
 }

src/main/java/org/jhove2/core/source/DirectorySource.java

 package org.jhove2.core.source;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.Date;
 
-import org.jhove2.annotation.ReportableProperty;
 import org.jhove2.core.JHOVE2;
 import org.jhove2.core.JHOVE2Exception;
 
 @Persistent
 public class DirectorySource
     extends AbstractSource
-    implements FileSystemSource
-{
-	/** Directory existence. */
-	protected boolean isExtant;
-
-	/** Directory readability. */
-	protected boolean isReadable;
-  
-	/** Directory path. */
-	protected String path;
+    implements NamedSource
+{  
+    /** Java {java.io.File} underlying the directory, if a physical directory
+     * on the file system.
+     */
+    protected File file;
+    
+	/** Directory name. */
+	protected String name;
 
 	protected DirectorySource(){
 		super();
 	 * Instantiate a new <code>DirectorySource</code>.
 	 * 
      * @param jhove2 JHOVE2 framework object
-	 * @param pathName
+	 * @param name
 	 *            Directory path name
-	 * @param sourceFactory SourceFactory which configures accessors for this source
 	 * @throws IOException
-	 * @throws FileNotFoundException
 	 * @throws JHOVE2Exception 
 	 * @throws JHOVE2Exception 
 	 */
-	protected DirectorySource(JHOVE2 jhove2, String pathName,
-	                          SourceFactory sourceFactory)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	protected DirectorySource(JHOVE2 jhove2, String name)
+	    throws IOException, JHOVE2Exception
 	{
-		this(jhove2, new File(pathName), sourceFactory);
+		this(jhove2, name, true);
 	}
-
+    
+    /**
+     * Instantiate a new <code>DirectorySource</code>.
+     * 
+     * @param jhove2 JHOVE2 framework object
+     * @param name
+     *            Directory path name
+     * @param fileSystemDirectory True if a physical directory on the file system
+     * @throws IOException
+     * @throws JHOVE2Exception 
+     */
+    protected DirectorySource(JHOVE2 jhove2, String name,
+                              boolean fileSystemDirectory)
+        throws IOException, JHOVE2Exception
+    {
+        super(jhove2);
+        
+        /* Is this is a physical directory (and not a directory embedded in
+         * a container, create a Java {@link java.io.File}.
+         */
+        this.file = null;
+        if (fileSystemDirectory) {
+            this.file = new File(name);
+        }
+        init(jhove2, name, this.file, fileSystemDirectory);
+    }
+    
+    /**
+     * Instantiate a new <code>DirectorySource</code>.
+     * 
+     * @param jhove2 JHOVE2 framework object
+     * @param file
+     *            Java {@link java.io.File} representing a directory
+     * @throws IOException
+     * @throws JHOVE2Exception 
+     */
+    protected DirectorySource(JHOVE2 jhove2, File file)
+        throws IOException, JHOVE2Exception
+    {
+        this(jhove2, file, true);
+    }
+    
 	/**
 	 * Instantiate a new <code>DirectorySource</code>.
 	 * 
      * @param jhove2 JHOVE2 framework object
 	 * @param file
 	 *            Java {@link java.io.File} representing a directory
-	 * @param sourceFactory  SourceFactory which configures accessors for this source
+	 * @param fileSystemDirectory True if a physical directory on the file
+	 *                            system, as opposed to a directory embedded
+	 *                            in a container
 	 * @throws IOException
-	 * @throws FileNotFoundException
 	 * @throws JHOVE2Exception 
 	 */
-	protected DirectorySource(JHOVE2 jhove2, File file, SourceFactory sourceFactory)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	protected DirectorySource(JHOVE2 jhove2, File file,
+	                          boolean fileSystemDirectory)
+	    throws IOException, JHOVE2Exception
 	{
-		super(jhove2, file);
-		this.setSourceAccessor(sourceFactory.createSourceAccessor(this));
-		this.path = file.getName();
-		try {
-			this.path = file.getCanonicalPath();
-		} catch (IOException e) {
-			/* Let path stay initialized to just the file name. */
-		}
-		this.isExtant = file.exists();
-		if (this.isExtant) {
-			this.isReadable = file.canRead();
-			File[] list = file.listFiles();
-			for (int i = 0; i < list.length; i++) {
-				Source source = sourceFactory.getSource(jhove2, list[i]);
-				source = this.addChildSource(source);
-			} 
+		super(jhove2);
+		
+		init(jhove2, file.getName(), file, fileSystemDirectory);
+	}
+	
+	/** Initialize the directory source.
+	 * @param jhove2 JHOVE2 framework object
+	 * @param name   Directory name
+	 * @param file   Directory file, if a physical directory
+	 * @param fileSystemDirectory True if a physical directory
+	 * @throws IOException
+	 * @throws JHOVE2Exception
+	 */
+	protected void init(JHOVE2 jhove2, String name, File file,
+	                    boolean fileSystemDirectory)
+	    throws IOException, JHOVE2Exception 
+	{
+        this.name = name;
+		if (fileSystemDirectory) { 
+		    /* Get child source units. */
+		    File[] list = file.listFiles();
+		    for (int i = 0; i < list.length; i++) {
+		        Source source = jhove2.getSourceFactory().getSource(jhove2,
+		                                                            list[i]);
+		        source = this.addChildSource(source);
+		    }
+		    /* Get file system-specific properties. */
+            String path = name;
+	        try {
+                path = file.getCanonicalPath();
+	        } catch (IOException e) {
+	            /* Let path stay initialized to just the directory name. */
+	        }
+            this.fileSystemProperties =
+                new FileSystemProperties(path, file.exists(), file.canRead(),
+                                         file.isHidden(), false,
+                                         new Date(file.lastModified()));
 		}
 		this.isAggregate = true;
 	}
 
-	/**
-	 * Get directory path.
-	 * 
-	 * @return Directory path
-	 */
-	@ReportableProperty(order = 1, value = "Directory path.")
-	public String getPath() {
-		return this.path;
-	}
-
     /**
      * Get directory source name.
      * 
      */
     @Override
     public String getSourceName() {
-        return this.path;
+        return this.name;
     }
-    
-	/**
-	 * Get directory existence.
-	 * 
-	 * @return True if directory exists
-	 */
-	@Override
-	public boolean isExtant() {
-		return this.isExtant;
-	}
-
-	/**
-	 * Get directory readability.
-	 * 
-	 * @return True if directory is readable
-	 */
-	@Override
-	public boolean isReadable() {
-		return this.isReadable;
-	}
-}
+ }

src/main/java/org/jhove2/core/source/FileSetSource.java

 
 package org.jhove2.core.source;
 
+import org.jhove2.core.JHOVE2;
 import com.sleepycat.persist.model.Persistent;
 
 /**
 		super();
 		this.isAggregate = true;
 	}
+	
+	/** Instantiate a new <code>FileSetSource</code>.
+	 * @param jhove2 JHOVE2 framework object
+	 */
+	protected FileSetSource(JHOVE2 jhove2) {
+	    super(jhove2);
+	}
 }

src/main/java/org/jhove2/core/source/FileSource.java

 package org.jhove2.core.source;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.io.InputStream;
+import java.nio.ByteOrder;
 import java.util.Date;
 
-import org.jhove2.annotation.ReportableProperty;
 import org.jhove2.core.JHOVE2;
 import org.jhove2.core.JHOVE2Exception;
+import org.jhove2.core.io.Input;
+import org.jhove2.core.io.InputFactory;
 
 
 import com.sleepycat.persist.model.Persistent;
 
 /**
- * File source unit. Represents physical file on file system.
+ * File source unit. Represents an abstract file, which can either be a
+ * physical file in file system or a file embedded inside of a container.
  * 
  * @author mstrong, slabrams
  */
 @Persistent
 public class FileSource
 	extends AbstractSource
-	implements MeasurableSource, FileSystemSource  
+	implements MeasurableSource, NamedSource  
 {
     /** Ending offset, in bytes, relative to the parent source.  If there is
      * no parent, the ending offset is the size.
      */
     protected long endingOffset;
- 
-	/** File existence. */
-	protected boolean isExtant;
-
-	/** File hiddeness. */
-	protected boolean isHidden;
-
-	/** File readability. */
-	protected boolean isReadable;
-
-	/** File specialness. */
-	protected boolean isSpecial;
+    
+    /** Backing file. */
+    protected File file;
 
 	/** File last modified date. */
 	protected Date lastModified;
 
-	/** File path name. */
-	protected String path;
+	/** File name. */
+	protected String name;
 
 	/** File size, in bytes. */
 	protected long size;
 	 * Instantiate a new <code>FileSource</code>.
 	 * 
      * @param jhove2 JHOVE2 framework object
-	 * @param pathName
-	 *            File path name
+	 * @param name
+	 *            File name
 	 * @throws FileNotFoundException
 	 *             File not found
 	 * @throws IOException
 	 *             I/O exception instantiating source
 	 * @throws JHOVE2Exception 
 	 */
-	protected FileSource(JHOVE2 jhove2, String pathName)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	protected FileSource(JHOVE2 jhove2, String name)
+	    throws JHOVE2Exception
 	{
-		this(jhove2, new File(pathName));
+	    this(jhove2, new File(name));
 	}
 	
 	@SuppressWarnings("unused")
 	private FileSource(){
 		super();
 	}
+	   
+    /**
+     * Instantiate a new file system <code>FileSource</code>.
+     * 
+     * @param jhove2 JHOVE2 framework object
+     * @param file
+     *            Java {@link java.io.File}
+     * @throws IOException
+     * @throws FileNotFoundException
+     * @throws JHOVE2Exception 
+     */
+    protected FileSource(JHOVE2 jhove2, File file)
+        throws JHOVE2Exception
+    {
+        this(jhove2, file, true);
+    }
+    
 	/**
 	 * Instantiate a new <code>FileSource</code>.
 	 * 
      * @param jhove2 JHOVE2 framework object
 	 * @param file
 	 *            Java {@link java.io.File}
+	 * @param fileSystemFile
+	 *            True if the file is a physical file on the file system, and 
+	 *            not embedded within a container
 	 * @throws IOException
 	 * @throws FileNotFoundException
 	 * @throws JHOVE2Exception 
 	 */
-	protected FileSource(JHOVE2 jhove2, File file)
-	    throws FileNotFoundException, IOException, JHOVE2Exception
+	protected FileSource(JHOVE2 jhove2, File file, boolean fileSystemFile)
+	    throws JHOVE2Exception
 	{
-		super(jhove2, file);
+		super(jhove2);
 
-		this.path = file.getName();
-		try {
-			this.path = file.getCanonicalPath();
-		} catch (IOException e) {
-			/* Let path stay initialized to just the file name. */
-		}
-		this.isExtant = file.exists();
-		if (this.isExtant) {
-			this.size = file.length();
-			this.isHidden = file.isHidden();
-			this.isReadable = file.canRead();
-			this.isSpecial = !file.isFile();
-			this.lastModified = new Date(file.lastModified());
-		}
-		else {
-			this.size = 0L;
-			this.isHidden = false;
-			this.isSpecial = false;
-		}
+		this.file = file;
+		this.name = file.getName();
+        this.size = file.length();
 		this.startingOffset = 0L;
 		this.endingOffset = this.size;
         if (this.size > 0L) {
             this.endingOffset--;
         }
+
+        if (fileSystemFile) {
+            /* Get file system-specific properties. */
+            String path = name;
+            try {
+                path = file.getCanonicalPath();
+            } catch (IOException e) {
+                /* Let path stay initialized to just the file name. */
+            }
+            this.fileSystemProperties =
+                new FileSystemProperties(path, file.exists(), file.canRead(),
+                                         file.isHidden(), !file.isFile(),
+                                         new Date(file.lastModified()));
+        }
 	}
 
     /** Get ending offset of the source unit, in bytes, relative to the
     public long getEndingOffset() {
         return this.endingOffset;
     }
+
+    /**
+     * Get {@link java.io.File} backing the source unit.
+     * 
+     * @return File backing the source unit
+     * @see org.jhove2.core.source.Source#getFile()
+     */
+    @Override
+    public File getFile() {
+        return this.file;
+    }
     
     /**
-     * Get file last modified date.
-     * 
-     * @return File last modified date
+     * Create and get {@link org.jhove2.core.io.Input} for the source unit. 
+     * If this method is called explicitly, then the corresponding Input.close()
+     * method must be called to avoid a resource leak.
+     * @param jhove2 JHOVE2 framework object
+     * @param order
+     *            Byte order
+     * @return Source unit input
+     * @throws IOException
+     *             I/O exception getting input
      */
-    @ReportableProperty(order = 2, value = "File last modified date.")
-    public Date getLastModified() {
-        return this.lastModified;
+    @Override
+    public Input getInput(JHOVE2 jhove2, ByteOrder order)
+        throws IOException
+    {
+        Input input = InputFactory.getInput(jhove2, this.file, this.isTemp, order);
+        if (input != null) {
+            input.setDeleteTempFileOnClose(this.deleteTempFileOnClose);
+        }
+        return input;
     }
     
-	/**
-	 * Get file path.
-	 * 
-	 * @return File path
-	 */
-	@ReportableProperty(order = 1, value = "File path.")
-	public String getPath() {
-		return this.path;
-	}
-
+    /**
+     * Get {@link java.io.InputStream} backing the source unit.
+     * If this method is called explicitly, then the corresponding
+     * InputStream.close() method must be called to avoid a resource leak. 
+     * 
+     * @return Input stream backing the source unit, or null if a Clump,
+     *         Directory, or FileSet source
+     * @throws FileNotFoundException  Backing file not found
+     * @throws IOException Backing file could not be created
+     * @see org.jhove2.core.source.Source#getInputStream()
+     */
+    @Override
+    public InputStream getInputStream()
+        throws FileNotFoundException, IOException
+    {
+        InputStream stream = null;
+        if (this.file != null) {
+            stream = new FileInputStream(this.file);
+        }
+        return stream;
+    }
+    
     /** Get size, in bytes.
      * @return Size
      */
     @Override
     public String getSourceName()
     {
-        return this.path; //sourceName;
+        return this.name;
     }
 
     /** Get starting offset of the source unit, in bytes, relative to the
     public long getStartingOffset() {
         return this.startingOffset;
     }
-    
-    /**
-     * Get file existence.
-     * 
-     * @return True if file exists
-     */
-    @Override
-    public boolean isExtant() {
-        return this.isExtant;
-    }
-
-    /**
-     * Get file hiddeness.
-     * 
-     * @return True if file is hidden
-     */
-    @ReportableProperty(order = 3, value = "File hiddeness: True if the file is "
-            + "hidden")
-    public boolean isHidden() {
-        return this.isHidden;
-    }
-
-	/**
-	 * Get file readability.
-	 * 
-	 * @return True if file is readable
-	 */
-    @Override
-	public boolean isReadable() {
-		return this.isReadable;
-	}
-
-	/**
-	 * Get file specialness.
-	 * 
-	 * @return True if file is special
-	 */
-	@ReportableProperty(order = 4, value = "File specialness: true if the file is "
-			+ "special.")
-	public boolean isSpecial() {
-		return this.isSpecial;
-	}
 }

src/main/java/org/jhove2/core/source/FileSystemProperties.java

+/**
+ * JHOVE2 - Next-generation architecture for format-aware characterization
+ *
+ * Copyright (c) 2010 by The Regents of the University of California,
+ * Ithaka Harbors, Inc., and The Board of Trustees of the Leland Stanford
+ * Junior University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ *
+ * o Neither the name of the University of California/California Digital
+ *   Library, Ithaka Harbors/Portico, or Stanford University, nor the names of
+ *   its contributors may be used to endorse or promote products derived from
+ *   this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jhove2.core.source;
+
+import java.util.Date;
+import org.jhove2.annotation.ReportableProperty;
+import org.jhove2.core.reportable.AbstractReportable;
+import com.sleepycat.persist.model.Persistent;
+
+/** File system properties,for {@link org.jhove2.core.source.Source} units
+ * that are physical files or directories on the file system.
+ * 
+ * @author slabrams
+ */
+@Persistent
+public class FileSystemProperties
+    extends AbstractReportable
+{ 
+    /** File existence. */
+    protected boolean isExtant;
+
+    /** File hiddeness. */
+    protected boolean isHidden;
+
+    /** File readability. */
+    protected boolean isReadable;
+
+    /** File specialness. */
+    protected boolean isSpecial;
+    
+    /** File last modified date. */
+    protected Date lastModified;
+    
+    /** File pathname. */
+    protected String path;
+
+    /** No argument constructor. */
+    public FileSystemProperties()
+    {
+        super();
+    }
+    
+    /** Instantiate a new <code>FileSystemProperties</code> reportable.
+     * @param path       File pathname
+     * @param isExtant   File is extant
+     * @param isReadable File is readable
+     * @param isHidden   File is hidden
+     * @param isSpecial  File is special
+     * @param lastModified File last modified date
+     */
+    public FileSystemProperties(String path, boolean isExtant,
+                                boolean isReadable, boolean isHidden,
+                                boolean isSpecial, Date lastModified) {
+        super();
+        
+        this.path         = path;
+        this.isExtant     = isExtant;
+        this.isReadable   = isReadable;
+        this.isHidden     = isHidden;
+        this.isSpecial    = isSpecial;
+        this.lastModified = lastModified;
+    }
+    
+    /**
+     * Get file last modified date.
+     * 
+     * @return File last modified date
+     */
+    @ReportableProperty(order = 2, value = "File last modified date.")
+    public Date getLastModified() {
+        return this.lastModified;
+    }
+    
+    /**
+     * Get file existence.
+     * 
+     * @return True if file exists
+     */
+    @ReportableProperty(order = 3, value = "File existence: true if the file exists")
+    public boolean isExtant() {
+        return this.isExtant;
+    }
+
+    /**
+     * Get file hiddeness.
+     * 
+     * @return True if file is hidden
+     */
+    @ReportableProperty(order = 5, value = "File hiddeness: True if the file is "
+            + "hidden")
+    public boolean isHidden() {
+        return this.isHidden;
+    }
+    
+    /**
+     * Get file readability.
+     * 
+     * @return True if file is readable
+     */
+    @ReportableProperty(order = 4, value = "File readability: true if the " +
+            "file is readable.")
+    public boolean isReadable() {
+        return this.isReadable;
+    }
+
+    /**
+     * Get file specialness.
+     * 
+     * @return True if file is special
+     */
+    @ReportableProperty(order = 6, value = "File specialness: true if the file is "
+            + "special.")
+    public boolean isSpecial() {
+        return this.isSpecial;
+    }
+    
+    /** Get file pathname.
+     * @return File pathname
+     */
+    @ReportableProperty(order = 1, value="File pathname.")
+    public String getPath() {
+        return this.path;
+    }
+ }

src/main/java/org/jhove2/core/source/FileSystemSource.java

-/**
- * JHOVE2 - Next-generation architecture for format-aware characterization
- *
- * Copyright (c) 2010 by The Regents of the University of California,
- * Ithaka Harbors, Inc., and The Board of Trustees of the Leland Stanford
- * Junior University.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * o Redistributions of source code must retain the above copyright notice,
- *   this list of conditions and the following disclaimer.
- *
- * o Redistributions in binary form must reproduce the above copyright notice,
- *   this list of conditions and the following disclaimer in the documentation
- *   and/or other materials provided with the distribution.
- *
- * o Neither the name of the University of California/California Digital
- *   Library, Ithaka Harbors/Portico, or Stanford University, nor the names of
- *   its contributors may be used to endorse or promote products derived from
- *   this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-package org.jhove2.core.source;
-
-import org.jhove2.annotation.ReportableProperty;
-import com.sleepycat.persist.model.Persistent;
-
-/** Interface for {@linkplain org.jhove2.core.source.Source source units} that are file
- *  system entities, that is, files or directories.
- * 
- * @author slabrams
- */
-@Persistent
-public interface FileSystemSource
-    extends NamedSource
-{
-    /**
-     * Get file existence.
-     * 
-     * @return True if file exists
-     */
-    @ReportableProperty(order = 1, value = "File existence: true if the file exists")
-    public boolean isExtant();
-
-    /**
-     * Get file readability.
-     * 
-     * @return True if file is readable
-     */
-    @ReportableProperty(order = 2, value = "File readability: true if the " +
-            "file is readable.")
-    public boolean isReadable();
-}

src/main/java/org/jhove2/core/source/Source.java

 	 */
 	public Source addChildSource(Source child) throws JHOVE2Exception;
 	
+	/** Add an extra properties {@link org.jhove2.core.reportable.Reportable}
+	 * to be associated with the source unit.  Extra properties are those not
+	 * known at the time the source unit is instantiated and which are not
+	 * associated with a particular {@link org.jhove2.module.format.FormatModule}.
+	 * @param properties Extra properties reportable
+	 * @return Source with extra properties added
+	 * @throws JHOVE2Exception
+	 */
+	public Source addExtraProperties(Reportable properties) throws JHOVE2Exception;
+	
 	/** Add a message to be associated with the source unit.
 	 * @param message Message to be associated with the source unit
 	 * @return Source with message added
 	 * @return Child source units
 	 * @throws JHOVE2Exception 
 	 */
-	@ReportableProperty(order=6, value="Child source units.")
+	@ReportableProperty(order=8, value="Child source units.")
 	public List<Source> getChildSources() throws JHOVE2Exception;
+	
+	/** Get extra properties.  Extra properties are those not known at the
+	 * time the source unit is instantiated but which are not associated with
+	 * a particular {@link org.jhove2.module.format.FormatModule}.
+	 * @return Extra properties
+	 * @throws JHOVE2Exception
+	 */
+	@ReportableProperty(order=2, value="Extra properties.")
+	public List<Reportable> getExtraProperties() throws JHOVE2Exception;
 
 	/**
 	 * Get temporary file deletion flag; if true, delete on close.
     /**
      * Get {@link java.io.File} backing the source unit.
      * 
-     * @return File backing the source unit, of null if a Clump or FileSet source
+     * @return File backing the source unit, of null if a Clump, Directory, or
+     * FileSet source
      */
     public File getFile();
+    
+    /** Get {@link org.jhove2.core.source.FileSystemProperties}, if the source
+     * is a physical file or directory in the file system.
+     * @return File system properties
+     */
+    @ReportableProperty(order=1, value="File system properties, if the source " +
+            "is a physical file or directory int the file system.")
+    public FileSystemProperties getFileSystemProperties();
 
     /**
      * Get little-endian {@link org.jhove2.core.io.Input} for the source unit
      * If this method is called explicitly, then the corresponding Input.close()
      * method must be called to avoid a resource leak.
      * @param jhove2 JHOVE2 framework
-     * @return Input for the source unit
+     * @return Input for the source unit, or null if a Clump, Directory, or
+     * FileSet source
      */
     public Input getInput(JHOVE2 jhove2)
-        throws FileNotFoundException, IOException;
+        throws IOException;
 
     /**
      * Get {@link org.jhove2.core.io.Input} for the source unit with the 
      * Input.close() method must be called to avoid a resource leak.
      * @param jhove2 JHOVE2 framework
      * @param order  Byte order
-     * @return Input for the source unit
+     * @return Input for the source unit, or null if a Clump, Directory, or
+     * FileSet source
      */
     public Input getInput(JHOVE2 jhove2, ByteOrder order)
-        throws FileNotFoundException, IOException;
+        throws IOException;
   
 	/**
 	 * Get {@link java.io.InputStream} for the file backing the source unit.
 	 * @throws FileNotFoundException Backing file not found
 	 * @throws IOException Backing file cannot be created
 	 */
-	public InputStream getInputStream() throws FileNotFoundException, IOException;
+	public InputStream getInputStream() throws IOException;
 
 	/**
 	 * Get copy of List of modules that processed the source unit.
 	 * @return Modules that processed the source unit
 	 * @throws JHOVE2Exception 
 	 */
-	@ReportableProperty(order=3, value="Modules that processed the source unit")
+	@ReportableProperty(order=5, value="Modules that processed the source unit")
 	public List<Module> getModules() throws JHOVE2Exception;
 
 	/**
 	 * @return Number of child source units
 	 * @throws JHOVE2Exception 
 	 */
-	@ReportableProperty(order=5, value="Number of child source units.")
+	@ReportableProperty(order=7, value="Number of child source units.")
 	public int getNumChildSources() throws JHOVE2Exception;
 	
 	/** Get messages associated with the source unit.
 	 * @return Source unit messages
 	 */
-	@ReportableProperty(order=2, value="Source unit messages.")
+	@ReportableProperty(order=3, value="Source unit messages.")
 	public List<Message> getMessages();
 
 	/**
 	 * Get list of presumptive formats for the source unit.
 	 * @return List of presumptive formats
 	 */
-	@ReportableProperty(order=1, value="Presumptive formats for the source.")
+	@ReportableProperty(order=4, value="Presumptive formats for the source.")
 	public Set<FormatIdentification> getPresumptiveFormats();
 	   
     /**
 	 * Get elapsed time processing this source unit.
 	 * @return Elapsed time
 	 */
-	@ReportableProperty(order=7, value="Timer info for this Source.")
+	@ReportableProperty(order=9, value="Timer info for this Source.")
 	public TimerInfo getTimerInfo();
 
     /** Aggregate source flag: true if an aggregate source.
      * @return Aggregate source flag
      */
-    @ReportableProperty(order=4, value="Aggregate source status: true if an " +
+    @ReportableProperty(order=6, value="Aggregate source status: true if an " +
         "aggregate source.")
     public boolean isAggregate();
     
 	 * @return Source with new deletion flag set
 	 * @throws JHOVE2Exception 
 	 */
-	public Source setDeleteTempOnClose(boolean flag) throws JHOVE2Exception;
+	public Source setDeleteTempFileOnClose(boolean flag) throws JHOVE2Exception;
 
     /** Set aggregate flag.
      * @param flag Aggregate flag: true if an aggregate
      */
     public Source setIsAggregate(boolean flag) throws JHOVE2Exception;
+    
+    /** Set temporary file flag.
+     * @param flag Temporary file flag; true if the backing file is temporary
+     */
+    public Source setIsTemp(boolean flag) throws JHOVE2Exception;
 
     /**
      * @param moduleParentSourceId the moduleParentSourceId to set

src/main/java/org/jhove2/core/source/SourceCounter.java

 	/** Number of pseudo-directory source units. */
 	protected int numFileSets;
 	
+	/** Number of URL source units. */
+	protected int numURLs;
+	
 	/**
 	 * Constructor
 	 */
 	 * @param source Source whose scope determines which counter to increment
 	 */
 	public void incrementSourceCounter(Source source){
-		if (source instanceof ClumpSource) {
+		if (source instanceof ByteStreamSource) {
+		    this.numBytestreams++;
+		} else if (source instanceof ClumpSource) {
 			this.numClumps++;
-		} else if (source instanceof DirectorySource
-				|| source instanceof ZipDirectorySource) {
+		} else if (source instanceof DirectorySource) {
 			this.numDirectories++;
-		} else if (source instanceof FileSource
-				|| source instanceof ZipFileSource) {
+		} else if (source instanceof FileSource) {
 			this.numFiles++;
 		} else if (source instanceof FileSetSource) {
 			this.numFileSets++;
+		} else if (source instanceof URLSource) {
+		    this.numURLs++;
 		}
 	}
 	
 		this.numDirectories = 0;
 		this.numFiles = 0;
 		this.numFileSets = 0; 
+		this.numURLs = 0;
 	}
 
 	/**
 		this.numFileSets++;
 	}
 	
+	/** Increment the number of URL source units. */
+	public void incrementNumURLs() {
+	    this.numURLs++;
+	}
+	
 	/**
 	 * Get number of aggregate source units processed.
 	 * 
 	 * @return Number of aggregate source units processed
 	 */
-	@ReportableProperty(order = 6, value = "Number of bytestream source units "
+	@ReportableProperty(order = 3, value = "Number of bytestream source units "
 		+ "processed.")
 		public int getNumBytestreamSources() {
 		return this.numBytestreams;
 	 * 
 	 * @return Number of clump source units processed
 	 */
-	@ReportableProperty(order = 3, value = "Number of clump source units "
+	@ReportableProperty(order = 7, value = "Number of clump source units "
 		+ "processed.")
 		public int getNumClumpSources() {
 		return this.numClumps;
 	 * 
 	 * @return Number of directory source units processed
 	 */
-	@ReportableProperty(order = 4, value = "Number of directory source units "
+	@ReportableProperty(order = 5, value = "Number of directory source units "
 		+ "processed, including both file system directories and Zip "
 		+ "entry directories.")
 		public int getNumDirectorySources() {
 	 * 
 	 * @return Number of file set source units processed
 	 */
-	@ReportableProperty(order = 2, value = "Number of file set source units "
+	@ReportableProperty(order = 6, value = "Number of file set source units "
 		+ "processed.")
 		public int getNumFileSetSources() {
 		return this.numFileSets;
 	 * 
 	 * @return Number of file source units processed
 	 */
-	@ReportableProperty(order = 5, value = "Number of file source units "
+	@ReportableProperty(order = 2, value = "Number of file source units "
 		+ "processed, including both file system files and Zip entry "
 		+ "files.")
 		public int getNumFileSources() {
 	@ReportableProperty(order = 1, value = "Number of source units processed.")
 	public int getNumSources() {
 		return this.numFileSets + this.numDirectories + this.numClumps
-		+ this.numFiles + this.numBytestreams;
+		+ this.numFiles + this.numBytestreams + this.numURLs;
 	}
 }

src/main/java/org/jhove2/core/source/SourceFactory.java

 package org.jhove2.core.source;
 
 import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URL;
 import java.util.List;
 	 * @param jhove2 JHOVE2 framework object
 	 * @param name Formatted object name
 	 * @return File, Directory, or URL Source unit
-	 * @throws FileNotFoundException
-	 *             File not found
 	 * @throws IOException
 	 *             I/O exception instantiating source
 	 * @throws JHOVE2Exception 
 	 */
 	public Source getSource(JHOVE2 jhove2, String name)
-	    throws FileNotFoundException, IOException, JHOVE2Exception;
+	    throws IOException, JHOVE2Exception;
  
 	/**
 	 * Get source unit from a Java {@link java.io.File}.
 	 * @param file
 	 *            Java {@link java.io.File}
 	 * @return File or Directory source unit
-	 * @throws FileNotFoundException
-	 *             File not found
 	 * @throws IOException
 	 *             I/O exception instantiating source
 	 * @throws JHOVE2Exception 
 	 */
 	public Source getSource(JHOVE2 jhove2, File file)
-		throws FileNotFoundException, IOException, JHOVE2Exception;
+		throws IOException, JHOVE2Exception;