--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2012 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.maps.eclipse;
+
+import java.awt.Image;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+
+import javax.imageio.ImageIO;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Platform;
+import org.osgi.framework.Bundle;
+import org.simantics.maps.ProvisionException;
+import org.simantics.maps.tile.ITileProvider;
+import org.simantics.maps.tile.TileKey;
+
+/**
+ * @author Tuukka Lehtonen
+ */
+public class DiskCachingTileProvider implements ITileProvider {
+
+ private final String CACHED_IMAGE_FORMAT = "png";
+
+ ITileProvider provider;
+
+ IPath cachePath;
+
+ boolean supportAlpha;
+
+// private ImageWriter writer;
+//
+// private ImageReader reader;
+//
+// private ImageTypeSpecifier noAlphaType = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR);
+//
+// private ImageTypeSpecifier alphaType = ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR);
+
+
+ public DiskCachingTileProvider(ITileProvider provider, Boolean supportAlpha) {
+ this.provider = provider;
+ this.supportAlpha = supportAlpha;
+ initCache();
+ }
+
+ @Override
+ public URI getSource() {
+ return provider.getSource();
+ }
+
+ @Override
+ public Rectangle2D getExtent() {
+ return provider.getExtent();
+ }
+
+ private void initCache() {
+ Bundle b = Platform.getBundle("org.simantics.maps");
+ if (b == null)
+ return;
+ IPath statePath = Platform.getStateLocation(b);
+ URI source = provider.getSource();
+ IPath cache = statePath.append("cache").append(source.getScheme()).append(source.getHost());
+
+ // Create the cache directory if it doesn't exist.
+ File f = cache.toFile();
+ if (!f.exists()) {
+ f.mkdirs();
+ } else if (!f.isDirectory()) {
+// FIXME
+// ErrorLogger.defaultLogError("Cache directory " + f.toString() + " already exists as a file, cannot use it for cache", new Exception());
+ return;
+ }
+
+ this.cachePath = cache;
+// System.out.println("MAP DATA CACHE: " + cachePath);
+
+// Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(CACHED_IMAGE_FORMAT);
+// writer = writers.next();
+// Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName(CACHED_IMAGE_FORMAT);
+// reader = readers.next();
+ }
+
+ private IPath toTileCachePath(TileKey key) {
+ return cachePath.append(key.getLevel() + "." + key.getX() + "." + key.getY());
+ }
+
+ private Image lookupFromDisk(TileKey key) {
+ if (cachePath == null)
+ return null;
+
+ IPath cachePath = toTileCachePath(key).addFileExtension(CACHED_IMAGE_FORMAT);
+ File f = cachePath.toFile();
+ if (f.exists()) {
+// ImageInputStream iis = null;
+ try {
+// iis = ImageIO.createImageInputStream(f);
+// ImageReadParam param = reader.getDefaultReadParam();
+// param.setDestinationType(supportAlpha ? alphaType : noAlphaType);
+// reader.setInput(iis, true, true);
+// BufferedImage img = reader.read(0, param);
+ BufferedImage img = ImageIO.read(f);
+ if (img != null) {
+ //System.out.println("[" + provider + "] Disk cache hit: " + key);
+ //System.out.println("[" + provider + "] image: " + img);
+ // Need to make sure that the type of the loaded image is
+ // something that can be rendered in an accelerated fashion.
+ if (img.getType() != BufferedImage.TYPE_CUSTOM)
+ return img;
+
+ BufferedImage img2 = null;
+ if (img.getAlphaRaster() != null) {
+ img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
+ } else {
+ img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
+ }
+ //System.out.println("[" + provider + "] image2: " + img2);
+
+ img.copyData(img2.getRaster());
+ return img2;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+// try {
+// iis.close();
+// } catch (IOException e) {
+// }
+ }
+ // Data is most likely corrupted, just destroy it.
+ f.delete();
+ }
+// System.out.println("Disk cache miss: " + key);
+ return null;
+ }
+
+ private void cacheToDisk(TileKey key, Image img) {
+ if (cachePath == null)
+ return;
+
+ if (!(img instanceof RenderedImage))
+ return;
+
+ IPath cachePath = toTileCachePath(key).addFileExtension(CACHED_IMAGE_FORMAT);
+ File f = cachePath.toFile();
+ try {
+ if (ImageIO.write((RenderedImage) img, CACHED_IMAGE_FORMAT, f)) {
+ //System.out.println("[" + provider + "] Disk cache write: " + key);
+ }
+ } catch (IOException e) {
+ // Caching failed, be silent about it.
+ }
+ }
+
+ @Override
+ public Image get(final TileKey key) throws ProvisionException {
+ Image img = lookupFromDisk(key);
+ if (img == null) {
+ img = provider.get(key);
+ final Image image = img;
+
+ // Write image to disk in the background
+ // TODO: use somekind of worker executor system instead of just threads.
+ new Thread() {
+ @Override
+ public void run() {
+ cacheToDisk(key, image);
+ }
+ }.start();
+ }
+ return img;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + " [" + provider.toString() + "]";
+ }
+
+}