TrackingFileManager { public Properties read( File file ) { synchronized ( getLock( file ) ) { FileLock lock = null; FileInputStream stream = null; try { if ( !file.exists() ) { return null; } stream = new FileInputStream( file ); lock = lock( stream.getChannel(), Math.max( 1, file.length() ), true ); Properties props = new Properties(); props.load( stream ); return props; } catch ( IOException e ) { logger.warn( "Failed to read resolution tracking file " + file, e ); } finally { release( lock, file ); close( stream, file ); } } return null; }  TrackingFileManager setLogger( Logger logger ); Properties read( File file ); Properties update( File file, Map<String, String> updates );  }
@Test public void testRead() throws Exception { TrackingFileManager tfm = new TrackingFileManager(); File propFile = TestFileUtils.createTempFile( "#COMMENT\nkey1=value1\nkey2 : value2" ); Properties props = tfm.read( propFile ); assertNotNull( props ); assertEquals( String.valueOf( props ), 2, props.size() ); assertEquals( "value1", props.get( "key1" ) ); assertEquals( "value2", props.get( "key2" ) ); assertTrue( "Leaked file: " + propFile, propFile.delete() ); props = tfm.read( propFile ); assertNull( String.valueOf( props ), props ); }
@Test public void testReadNoFileLeak() throws Exception { TrackingFileManager tfm = new TrackingFileManager(); for ( int i = 0; i < 1000; i++ ) { File propFile = TestFileUtils.createTempFile( "#COMMENT\nkey1=value1\nkey2 : value2" ); assertNotNull( tfm.read( propFile ) ); assertTrue( "Leaked file: " + propFile, propFile.delete() ); } }
@Test public void testLockingOnCanonicalPath() throws Exception { final TrackingFileManager tfm = new TrackingFileManager(); final File propFile = TestFileUtils.createTempFile( "#COMMENT\nkey1=value1\nkey2 : value2" ); final List<Throwable> errors = Collections.synchronizedList( new ArrayList<Throwable>() ); Thread[] threads = new Thread[4]; for ( int i = 0; i < threads.length; i++ ) { String path = propFile.getParent(); for ( int j = 0; j < i; j++ ) { path += "/."; } path += "/" + propFile.getName(); final File file = new File( path ); threads[i] = new Thread() { public void run() { try { for ( int i = 0; i < 1000; i++ ) { assertNotNull( tfm.read( file ) ); } } catch ( Throwable e ) { errors.add( e ); } } }; } for ( int i = 0; i < threads.length; i++ ) { threads[i].start(); } for ( int i = 0; i < threads.length; i++ ) { threads[i].join(); } assertEquals( Collections.emptyList(), errors ); }