FileSystemBinaryStore extends AbstractBinaryStore { @Override public BinaryValue storeValue( InputStream stream, boolean markAsUnused ) throws BinaryStoreException { File tmpFile = null; BinaryValue value = null; try { HashingInputStream hashingStream = SecureHash.createHashingStream(Algorithm.SHA_1, stream); tmpFile = File.createTempFile(TEMP_FILE_PREFIX, TEMP_FILE_SUFFIX); IoUtil.write(hashingStream, new BufferedOutputStream(new FileOutputStream(tmpFile)), AbstractBinaryStore.MEDIUM_BUFFER_SIZE); byte[] sha1 = hashingStream.getHash(); BinaryKey key = new BinaryKey(sha1); final long numberOfBytes = tmpFile.length(); if (numberOfBytes < getMinimumBinarySizeInBytes()) { byte[] content = IoUtil.readBytes(tmpFile); tmpFile.delete(); value = new InMemoryBinaryValue(this, key, content); } else { value = saveTempFileToStore(tmpFile, key, numberOfBytes); if (markAsUnused) { markAsUnused(key); } } return value; } catch (IOException e) { throw new BinaryStoreException(e); } catch (NoSuchAlgorithmException e) { throw new SystemFailureException(e); } finally { if (tmpFile != null) { try { tmpFile.delete(); } catch (Throwable t) { Logger.getLogger(getClass()).warn(t, JcrI18n.unableToDeleteTemporaryFile, tmpFile.getAbsolutePath(), t.getMessage()); } } } } protected  FileSystemBinaryStore( File directory ); protected  FileSystemBinaryStore( File directory, File trash ); static FileSystemBinaryStore create( File directory, File trash ); File getDirectory(); @Override BinaryValue storeValue( InputStream stream, boolean markAsUnused ); @Override InputStream getInputStream( BinaryKey key ); @Override void markAsUsed( Iterable<BinaryKey> keys ); void upgradeTrashContentFormat(); @Override void markAsUnused( Iterable<BinaryKey> keys ); @Override void removeValuesUnusedLongerThan( long minimumAge,
                                              TimeUnit unit ); @Override String getExtractedText( BinaryValue source ); @Override void storeExtractedText( BinaryValue source,
                                       String extractedText ); @Override Iterable<BinaryKey> getAllBinaryKeys();  }
@Test public void multipleThreadsShouldReadTheSameFile() throws Exception { final String textBase = "The quick brown fox jumps over the lazy dog"; StringBuilder builder = new StringBuilder(); Random rand = new Random(); while (builder.length() <= MIN_BINARY_SIZE) { builder.append(textBase.substring(0, rand.nextInt(textBase.length()))); } final String text = builder.toString(); final Binary storedValue = store.storeValue(new ByteArrayInputStream(text.getBytes()), false); ExecutorService executor = Executors.newFixedThreadPool(3); try { Callable<String> readingTask = () -> { File tempFile = File.createTempFile("test-binary-store", "bin"); try { FileOutputStream fos = new FileOutputStream(tempFile); InputStream is = storedValue.getStream(); byte[] buff = new byte[100]; int available; while ((available = is.read(buff)) != -1) { fos.write(buff, 0, available); } fos.close(); return IoUtil.read(tempFile); } finally { tempFile.delete(); } }; List<Callable<String>> tasks = Arrays.asList(readingTask, readingTask, readingTask); List<Future<String>> futures = executor.invokeAll(tasks, 5, TimeUnit.SECONDS); for (Future<String> future : futures) { assertEquals(text, future.get()); } } finally { executor.shutdownNow(); } }