| /******************************************************************************* |
| * Copyright (c) 2010 Nokia and others. |
| * 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: |
| * Nokia - Initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.cdt.debug.edc.internal; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.io.ObjectStreamClass; |
| import java.io.Serializable; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.IPath; |
| |
| public class PersistentCache { |
| |
| private class CacheEntry { |
| |
| private String identifier; |
| private long freshness; |
| private Serializable data; |
| private IPath location; |
| |
| public CacheEntry(String identifier, Serializable data, long freshness) { |
| this.identifier = identifier; |
| this.freshness = freshness; |
| this.data = data; |
| this.location = getDefaultLocation().append(Integer.toString(identifier.hashCode())).addFileExtension("txt");; |
| } |
| |
| public CacheEntry(ObjectInputStream ois) throws Exception { |
| this.identifier = (String) ois.readObject(); |
| this.freshness = (Long) ois.readObject(); |
| this.data = (Serializable) ois.readObject(); |
| this.location = getDefaultLocation().append(Integer.toString(identifier.hashCode())).addFileExtension("txt");; |
| } |
| |
| public IPath getLocation() { |
| return location; |
| } |
| |
| @SuppressWarnings("unchecked") |
| private <T> T getData(Class<T> expectedClass) { |
| if (expectedClass.isInstance(data)) |
| return (T) data; |
| else |
| return null; |
| } |
| |
| private long getFreshness() { |
| return freshness; |
| } |
| |
| private void flush() throws Exception { |
| File cacheFile = getLocation().toFile(); |
| if (!cacheFile.exists()) |
| { |
| cacheFile.getParentFile().mkdirs(); |
| cacheFile.createNewFile(); |
| } |
| FileOutputStream fos = new FileOutputStream(cacheFile); |
| ObjectOutputStream oos = new ObjectOutputStream(fos); |
| oos.writeObject(identifier); |
| oos.writeObject(freshness); |
| oos.writeObject(data); |
| fos.close(); |
| if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) { |
| EDCTrace.getTrace().trace(null, "Cache flush: " + identifier + " data: " + data); |
| } |
| } |
| |
| public void delete() { |
| File cacheFile = getLocation().toFile(); |
| if (cacheFile.exists()) |
| { |
| cacheFile.delete(); |
| } |
| } |
| |
| } |
| |
| private Map<String, CacheEntry> caches = Collections.synchronizedMap(new HashMap<String, CacheEntry>()); |
| private IPath defaultLocation; |
| |
| public PersistentCache(IPath defaultLocation) { |
| this.defaultLocation = defaultLocation; |
| } |
| |
| public CacheEntry getCache(String identifier){ |
| CacheEntry result = caches.get(identifier); |
| return result; |
| } |
| |
| public boolean hasCachedData(String cacheIdentifier) { |
| return caches.containsKey(cacheIdentifier); |
| } |
| |
| synchronized public <T> T getCachedData(String cacheIdentifier, T expectedClass, long freshness) { |
| @SuppressWarnings("unchecked") |
| T result = (T) getCachedData(cacheIdentifier, expectedClass.getClass(), freshness); |
| if (result == null) |
| { |
| putCachedData(cacheIdentifier, (Serializable) expectedClass, freshness); |
| result = expectedClass; |
| } |
| return result; |
| } |
| |
| synchronized public <T> T getCachedData(String cacheIdentifier, Class<T> expectedClass, long freshness) { |
| // freshness = 0; |
| CacheEntry cache = caches.get(cacheIdentifier); |
| |
| if (cache == null) |
| { |
| cache = loadCachedData(getDefaultLocation(), cacheIdentifier); |
| if (cache != null) |
| caches.put(cacheIdentifier, cache); |
| } |
| |
| if (cache != null) |
| { |
| long cachedFreshness = cache.getFreshness(); |
| T result = cache.getData(expectedClass); |
| if (cachedFreshness == freshness && result != null) |
| { |
| if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) { |
| EDCTrace.getTrace().trace(null, "Cache get data: " + cacheIdentifier + " data: " + result); |
| } |
| return result; |
| } |
| else |
| { |
| if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) { |
| EDCTrace.getTrace().trace(null, "Stale data. cachedFreshness: " + cachedFreshness + " freshness: " + result + " cache: " + cache); |
| } |
| caches.remove(cache); |
| cache.delete(); |
| } |
| } |
| |
| return null; |
| } |
| |
| private CacheEntry loadCachedData(IPath location, String cacheIdentifier) { |
| IPath flushPath = location.append(Integer.toString(cacheIdentifier.hashCode())).addFileExtension("txt"); |
| |
| if (flushPath.toFile().exists()) |
| { |
| try { |
| final ClassLoader classLoader = EDCDebugger.getDefault().getClass().getClassLoader(); |
| FileInputStream fis = new FileInputStream(flushPath.toFile()); |
| ObjectInputStream ois = new ObjectInputStream(fis) { |
| |
| @Override |
| protected Class<?> resolveClass(ObjectStreamClass desc) |
| throws IOException, ClassNotFoundException { |
| String name = desc.getName(); |
| try { |
| return classLoader.loadClass(name); |
| } catch (ClassNotFoundException e) { |
| return super.resolveClass(desc); |
| } |
| }}; |
| return new CacheEntry(ois); |
| } catch (Exception e) {} |
| } |
| |
| return null; |
| } |
| |
| public void putCachedData(String cacheIdentifier, Serializable data, long freshness) |
| { |
| CacheEntry cache = new CacheEntry(cacheIdentifier, data, freshness); |
| caches.put(cacheIdentifier, cache); |
| if (EDCTrace.PERSISTENT_CACHE_TRACE_ON) { |
| EDCTrace.getTrace().trace(null, "Cache put data: " + cacheIdentifier + " data: " + data); |
| } |
| } |
| |
| public void flushAll() { |
| Collection<CacheEntry> allCaches = caches.values(); |
| for (CacheEntry entry : allCaches) { |
| try { |
| entry.flush(); |
| } catch (Exception e) { |
| EDCDebugger.getMessageLogger().logException(e); |
| } |
| } |
| caches.clear(); |
| } |
| |
| public IPath getDefaultLocation() { |
| return defaultLocation; |
| } |
| |
| public void setDefaultLocation(IPath defaultLocation) { |
| this.defaultLocation = defaultLocation; |
| } |
| |
| } |