Java tutorial
/* * jBrowserDriver (TM) * Copyright (C) 2014-2016 Machine Publishers, LLC and the jBrowserDriver contributors * https://github.com/MachinePublishers/jBrowserDriver * * Licensed 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 com.machinepublishers.jbrowserdriver; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.HashSet; import java.util.Set; import org.apache.commons.codec.digest.DigestUtils; import org.apache.http.client.cache.HttpCacheEntry; import org.apache.http.client.cache.HttpCacheStorage; import org.apache.http.client.cache.HttpCacheUpdateCallback; import org.apache.http.client.cache.HttpCacheUpdateException; class HttpCache implements HttpCacheStorage { private final File cacheDir; HttpCache(File cacheDir) { this.cacheDir = cacheDir; } /** * {@inheritDoc} */ @Override public void updateEntry(String key, HttpCacheUpdateCallback callback) throws IOException, HttpCacheUpdateException { HttpCacheEntry entry = callback.update(getEntry(key)); putEntry(key, entry); } /** * {@inheritDoc} */ @Override public void removeEntry(String key) throws IOException { try (Lock lock = new Lock(new File(cacheDir, DigestUtils.sha1Hex(key)), false, false)) { lock.file.delete(); } catch (FileNotFoundException e) { //ignore } } /** * {@inheritDoc} */ @Override public void putEntry(String key, HttpCacheEntry entry) throws IOException { try (Lock lock = new Lock(new File(cacheDir, DigestUtils.sha1Hex(key)), false, true)) { BufferedOutputStream bufferOut = new BufferedOutputStream(lock.streamOut); try (ObjectOutputStream objectOut = new ObjectOutputStream(bufferOut)) { objectOut.writeObject(entry); } } } /** * {@inheritDoc} */ @Override public HttpCacheEntry getEntry(String key) throws IOException { try (Lock lock = new Lock(new File(cacheDir, DigestUtils.sha1Hex(key)), true, false)) { BufferedInputStream bufferIn = new BufferedInputStream(lock.streamIn); try (ObjectInputStream objectIn = new ObjectInputStream(bufferIn)) { return (HttpCacheEntry) objectIn.readObject(); } catch (Throwable t) { LogsServer.instance().exception(t); } } catch (FileNotFoundException e) { return null; } return null; } private static class Lock implements Closeable { private static final int MAX_RETRIES = 50; private static final int RETRY_SLEEP = 100; private static final Set<String> locks = new HashSet<String>(); private String lockName; private File file; private FileLock fileLock; private FileInputStream streamIn; private FileOutputStream streamOut; private FileChannel channel; Lock(File file, boolean read, boolean create) throws IOException { this.file = file; this.lockName = file.getAbsolutePath(); synchronized (locks) { while (true) { try { if (!locks.contains(lockName)) { locks.add(lockName); break; } else { locks.wait(); } } catch (Throwable t) { } } } for (int i = 0; i < MAX_RETRIES; i++) { if (i > 0) { try { Thread.sleep(RETRY_SLEEP); } catch (InterruptedException e2) { } } try { if (create) { file.createNewFile(); } if (read) { streamIn = new FileInputStream(file); channel = streamIn.getChannel(); } else { streamOut = new FileOutputStream(file); channel = streamOut.getChannel(); } fileLock = channel.lock(0, Long.MAX_VALUE, read); break; } catch (Throwable t) { if (!create && t instanceof FileNotFoundException) { close(); throw t; } if (i + 1 == MAX_RETRIES) { LogsServer.instance().exception(t); close(); if (t instanceof IOException) { throw t; } throw new IOException(t); } closeStreams(); } } } private void closeStreams() { if (streamIn != null) { try { streamIn.close(); } catch (Throwable t) { LogsServer.instance().exception(t); } } if (streamOut != null) { try { streamOut.close(); } catch (Throwable t) { LogsServer.instance().exception(t); } } } /** * {@inheritDoc} */ @Override public void close() { if (fileLock != null && channel != null && channel.isOpen()) { try { fileLock.release(); } catch (Throwable t) { LogsServer.instance().exception(t); } } closeStreams(); synchronized (locks) { locks.remove(lockName); locks.notifyAll(); } } } }