private FetchEntry getFetchEntry(String urlString, URL url) { ImageEntry imageEntry = new ImageEntry(urlString); String hash = toHexString(shaHash.get().digest(urlString.getBytes(ClientConfiguration.UTF8_CHARSET))); String cacheFileName = getCacheFileName(hash, urlString); imageEntry.cacheFile = Paths.get(cacheFileName); // from url FetchEntry fetchEntry = new FetchEntry(imageEntry); fetchEntry.url = url; // from cache Path cachePath = Paths.get(cacheFileName); if (Files.exists(cachePath)) { FetchEntry cacheFetchEntry = new FetchEntry(imageEntry); try { cacheFetchEntry.url = cachePath.toUri().toURL(); } catch (MalformedURLException e) { throw new AssertionError(e); } cacheFetchEntry.setAlternateEntry(fetchEntry); fetchEntry = cacheFetchEntry; } else { logger.debug("Cache miss: {}", urlString); } return fetchEntry; }
/** * 画像を取得し、imageSetterを呼び出す。 * * <p>フェッチに失敗したときは{@link ImageSetter#onException(Exception, ConnectionInfo)}が呼び出される * * @param imageSetter 画像セッター * @param url URL * @return キャッシュヒットしたかどうか * @throws InterruptedException 割り込まれた。 */ public boolean setImageIcon(ImageSetter imageSetter, URL url) throws InterruptedException { String urlString = url.toString(); ImageEntry imageEntry = cachedImages.get(urlString); if (imageEntry == null) { FetchEntry fetchEntry = fetchEntryMap.get(urlString); FetchEntry newEntry = null; if (fetchEntry == null) { newEntry = getFetchEntry(urlString, url); fetchEntry = fetchEntryMap.putIfAbsent(urlString, newEntry); } if (fetchEntry == null) { newEntry.addSetter(imageSetter); configuration.addJob(JobQueue.PRIORITY_UI, new ImageFetcher(newEntry)); return false; } else { synchronized (fetchEntry) { if (fetchEntry.isFinished()) { imageEntry = fetchEntry.imageEntry; } else { fetchEntry.addSetter(imageSetter); return false; } } } } if (imageEntry instanceof ErrorImageEntry) { return false; } else { imageSetter.setImageRecursively(imageEntry.image); return true; } }
@Override public void onException(URLConnection connection, IOException e) { URL url = entry.url; if (connection instanceof HttpURLConnection) { int responseCode; try { responseCode = ((HttpURLConnection) connection).getResponseCode(); if (responseCode >= 400 && responseCode < 500) { // CS-IGNORE // url is not local cache cachedImages.put(entry.getImageUrl(), new ErrorImageEntry(url, e)); if (responseCode == HttpURLConnection.HTTP_NOT_FOUND) { logger.warn("not found: url={}", url); } else { logger.warn("Error while fetching: url={}, statusCode={}", url, responseCode, e); } } else { logger.warn("Error while fetching: url={}, statusCode={}", url, responseCode, e); } } catch (IOException responseCodeException) { logger.warn("Cannot retrieve http status code", responseCodeException); } } else { logger.warn("Error while fetching: {}", url, e); } if (entry.getAlternateEntry() != null) { entry = entry.getAlternateEntry(); configuration.addJob(this); } }
@Override public void run() { try { fetchImage(entry); ImageSetter setter = entry.getSetter(); if (setter != null) { setter.setImageRecursively(entry.imageEntry.image); } fetchEntryMap.remove(entry.getImageUrl()); } catch (InterruptedException e) { logger.warn("Interrupted: {}", entry.url); } }
/** * 画像を取得する。 * * @param entry イメージエントリ * @throws java.lang.InterruptedException interrupted */ protected void fetchImage(FetchEntry entry) throws InterruptedException { synchronized (entry) { if (entry.isFinished()) { return; } byte[] imageData = NetworkSupport.fetchContents(entry.connectionInfo); ImageEntry imageEntry = entry.imageEntry; imageEntry.rawData = imageData; imageEntry.image = Toolkit.getDefaultToolkit().createImage(imageData); cachedImages.put(entry.getImageUrl(), entry.imageEntry); configuration.addJob(JobQueue.PRIORITY_IDLE, new ImageFlusher(imageEntry)); } }
/** * 画像セッターを追加する * * @param setter セッター */ public synchronized void addSetter(ImageSetter setter) { if (this.setter == null) { this.setter = setter; if (alternateEntry != null) { alternateEntry.addSetter(setter); } } else { this.setter.addSetter(setter); } }
/** * インスタンス生成 * * @param entry フェッチエントリ * @throws InterruptedException コネクション確立中に割り込まれた */ public ImageFetcher(FetchEntry entry) throws InterruptedException { this.entry = entry; entry.connectionInfo = NetworkSupport.openConnection(entry.url, this); }
/** * セッターを設定する * * @param setter セッター */ public synchronized void setSetter(ImageSetter setter) { this.setter = setter; if (alternateEntry != null) { alternateEntry.setSetter(setter); } }