Skip to content

Commit

Permalink
#5 disc storage enabled; now without storage limit
Browse files Browse the repository at this point in the history
  • Loading branch information
kpietak committed Apr 23, 2013
1 parent 3786d23 commit 8edd308
Show file tree
Hide file tree
Showing 12 changed files with 707 additions and 313 deletions.
7 changes: 7 additions & 0 deletions pl.edu.agh.cast.map/.checkstyle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>

<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">
<fileset name="all" enabled="true" check-config-name="CAST Checks" local="false">
<file-match-pattern match-pattern="." include-pattern="true"/>
</fileset>
</fileset-config>
3 changes: 2 additions & 1 deletion pl.edu.agh.cast.map/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ Require-Bundle: org.eclipse.ui,
org.eclipse.gef;bundle-version="3.9.0",
com.google.guava;bundle-version="13.0.1",
org.eclipse.e4.ui.di;bundle-version="0.10.1",
pl.edu.agh.cast.common;bundle-version="1.4.0"
pl.edu.agh.cast.common;bundle-version="1.4.0",
org.eclipse.core.resources;bundle-version="3.8.1"
Bundle-ActivationPolicy: lazy
Bundle-RequiredExecutionEnvironment: JavaSE-1.7
Import-Package: javax.inject;version="1.0.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
package pl.edu.agh.cast.map.cache;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.apache.log4j.Logger;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;

import pl.edu.agh.cast.map.config.IMapConfigurationProvider;
import pl.edu.agh.cast.map.storage.DiscStorageStrategy;
import pl.edu.agh.cast.map.storage.IDiscStorageStrategy;
import pl.edu.agh.cast.map.storage.ITileStorageStrategy;
import pl.edu.agh.cast.util.FileUtil;

/**
* Cache map's tiles on disc.
*
*/
public class DiscMapCache implements IMapCache {

/**
* Logger for this class.
*/
private static Logger log = Logger.getLogger(DiscMapCache.class);

/**
* Limit of storage (In megabytes). If -1 than there is no storage limit.
*/
private int storageLimit;

/**
* Strategy of storage map's tiles.
*/
private IDiscStorageStrategy storageStrategy;

/**
* Keeps information of how many space is used by disc cache (in bytes). <b>CAUTION:</b> this value is obtained in asynchronous way, so
* may not be available. If the value has not be establish yet than <code>-1</code> will be returned.
*/
private long currentStorage = -1L;

/**
* Constructor.
*
* @param storageStrategy
* Strategy of storing map tiles.
* @param storageLimit
* Limit of storage (In MB). If -1 than there is no storage limit.
*/
public DiscMapCache(IDiscStorageStrategy storageStrategy, int storageLimit) {
this.storageStrategy = storageStrategy;
this.storageLimit = storageLimit;
}

// BEGIN API Methods

/**
* Creates instance of {@link IDiscStorageStrategy}. Appropriate configuration is is obtained from application's settings (stored in
* {@link IPreferenceStore}).
*
* @param tileStorageStrategy
* Tiles storage strategy which is crucial for creating disc storage strategy.
* @return Instance of {@link IDiscStorageStrategy}.
*/
public static IDiscStorageStrategy createDiscStorageStrategy(ITileStorageStrategy tileStorageStrategy, IMapConfigurationProvider config) {
String storageDirectory = config.discCacheLocation();
IDiscStorageStrategy result = new DiscStorageStrategy(new File(storageDirectory), tileStorageStrategy);

return result;
}

/**
* Creates instance of {@link DiscyMapCache}. Appropriate disc cache's configuration is obtained from application's settings (stored in
* {@link IPreferenceStore}). If disc cache is disabled in application's setting than <code>null</code> will be returned.
*
* @param tileStorageStrategy
* Tile storage strategy (obtainable from {@link pl.edu.agh.cast.map.editor.driver.IMapDriver}).
*
* @return Instance of {@link DiscMapCache} or <code>null</code> is memory cache is disabled in application's
*/
public static DiscMapCache createDiscMapCache(ITileStorageStrategy tileStorageStrategy, IMapConfigurationProvider config) {

DiscMapCache result = null;

if (config.discCacheEnabled()) {
IDiscStorageStrategy discStorageStrategy = createDiscStorageStrategy(tileStorageStrategy, config);
boolean limitEnabled = config.discCacheLimitEnabled();
int storageLimit = config.discCacheLimit();
result = new DiscMapCache(discStorageStrategy, limitEnabled ? storageLimit : -1);
}

return result;
}

/**
* {@inheritDoc}
*
* @see pl.edu.agh.cast.map.editor.cache.IMapCache#getTile(int, int, int)
*/
@Override
public ImageData getTile(int zoom, int column, int row) {
File tilePath = storageStrategy.getPathToTile(zoom, column, row);

ImageData tile = null;
if (tilePath.exists()) {
byte[] data = null;
try {
FileInputStream fis = new FileInputStream(tilePath);
data = FileUtil.streamToByteArray(fis);
fis.close();
tile = new ImageData(new ByteArrayInputStream(data));
} catch (FileNotFoundException e) {
log.error("Cannot find tile: " + tilePath.getAbsolutePath(), e); //$NON-NLS-1$
} catch (IOException e) {
log.error("Exception during obtaining tile: " + tilePath.getAbsolutePath(), e); //$NON-NLS-1$
}
}

return tile;
}

/**
* {@inheritDoc}
*
* @see pl.edu.agh.cast.map.editor.cache.IMapCache#saveTile(int, int, int, org.eclipse.swt.graphics.ImageData)
*/
@Override
public void saveTile(int zoom, int column, int row, ImageData tile) {
File tilePath = storageStrategy.getPathToTile(zoom, column, row);
File tileDirectory = tilePath.getParentFile();

if (!tileDirectory.exists()) {
tileDirectory.mkdirs();
}

if (!tilePath.exists()) {
try {
long approximateSize = tile.width * tile.height * (tile.depth / 8);

if (!isLimited() || (currentStorage + approximateSize) / 1048576.0 <= storageLimit) {
FileOutputStream fos = new FileOutputStream(tilePath);
ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] { tile };
imageLoader.save(fos, SWT.IMAGE_PNG);
fos.close();

if (currentStorage != -1L) {
currentStorage += tilePath.length();
}
} else {
log.info("Disc cache is full. Cannot save tile: " + tilePath.getAbsolutePath()); //$NON-NLS-1$
}

} catch (FileNotFoundException e) {
log.error("Cannot save tile to: " + tilePath.getAbsolutePath(), e); //$NON-NLS-1$
} catch (IOException e) {
log.error("IOException during saving tile: " + tilePath.getAbsolutePath(), e); //$NON-NLS-1$
}
} else {
if (log.isDebugEnabled()) {
log.debug("Attempt of saving tile that already exists: " + tilePath.getAbsolutePath()); //$NON-NLS-1$
}
}

}

/**
* {@inheritDoc}
*
* @see pl.edu.agh.cast.common.IDisposable#dispose()
*/
@Override
public void dispose() {
}

// END API Methods

/**
* Return flag that indicates whether disc cache is limited.
*
* @return Flag that indicates whether disc cache is limited.
*/
private boolean isLimited() {
return storageLimit != -1 && currentStorage != -1L;
}

// BEGIN Inner Classes

/**
* Runnable that is responsible for obtaining value of discCacheSize in asynchronous way.
*/
private class DiscCacheSizeObtainer implements Runnable {
/**
* Tiles storage strategy.
*/
private List<IDiscStorageStrategy> storageStrategies;

/**
* Constructor.
*
* @param storageStrategy
* Tiles storage strategy.
*/
public DiscCacheSizeObtainer(List<IDiscStorageStrategy> storageStrategies) {
this.storageStrategies = storageStrategies;
}

/**
* {@inheritDoc}
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
long storage = 0;
LinkedList<File> dirToVisit = new LinkedList<>();
for (IDiscStorageStrategy storageStrategy : storageStrategies) {
dirToVisit.add(storageStrategy.getPathToRoot());
}

while (!dirToVisit.isEmpty()) {
File[] listFiles = dirToVisit.removeFirst().listFiles();

if (listFiles != null) {
for (File file : listFiles) {
if (Thread.currentThread().isInterrupted()) {
return;
}

if (file.isDirectory()) {
dirToVisit.add(file);
} else if (file.isFile()) {
storage += file.length();
}
}
}
}

currentStorage = new Long(storage);
}

}

// END Inner Classes

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public interface IMapConfigurationProvider {

int discCacheLimit();

String discCacheLocation();

boolean memoryCacheEnabled();

int memoryCacheLimit();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,39 @@

import pl.edu.agh.cast.map.provider.IMapProvider;


public interface IMapConfigurator extends IMapConfigurationProvider {

// Disc cache
// Disc cache

void enableDiscCache(boolean enabled);

void enableDiscCacheLimit(boolean enabled);

/**
*
* @param limit
* in MB
*/
void setDiscCacheLimit(int limit);

void setDiscCacheLocation(String location);

void enableDiscCache(boolean enabled);
// Memory cache

void enableDiscCacheLimit(boolean enabled);
void enableMemoryCache(boolean enabled);

/**
*
* @param limit
* in MB
*/
void setDiscCacheLimit(int limit);
/**
*
* @param limit
* in MB
*/
void setMemoryCacheLimit(int limit);

// Memory cache
// Map providers

void enableMemoryCache(boolean enabled);
void addMapProvider(IMapProvider mapProvider);

/**
*
* @param limit
* in MB
*/
void setMemoryCacheLimit(int limit);
void removeMapProvider(IMapProvider mapProvider);

// Map providers

void addMapProvider(IMapProvider mapProvider);

void removeMapProvider(IMapProvider mapProvider);

}
Loading

0 comments on commit 8edd308

Please sign in to comment.