package com.limegroup.gnutella.library;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
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.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.limewire.io.IOUtils;
import org.limewire.util.CommonUtils;
import org.limewire.util.GenericsUtils;
/**
* A container for storing serialized objects to disk.
* This supports only storing objects that fit in the Collections framework.
* Either Collections or Maps.
* All collections are returned as synchronized on this container.
*/
@Deprecated
class Container {
private static final Log LOG = LogFactory.getLog(Container.class);
private final Map<String, Collection<File>> STORED = new HashMap<String, Collection<File>>();
private final String filename;
/**
* Constructs a new container with the given filename.
* It will always save to this name in the user's
* setting's directory, also loading the data from disk.
*/
Container(String name) {
filename = name;
load();
}
/**
* Loads data from disk.
*/
void load() {
// Read without grabbing the lock.
Map<String, Collection<File>> read = readFromDisk();
synchronized(this) {
// Simple case -- no stored data yet.
if(STORED.isEmpty()) {
STORED.putAll(read);
} else {
// If data was stored, we can't replace, we have to refresh.
for(Map.Entry<String, Collection<File>> entry : read.entrySet()) {
String k = entry.getKey();
Collection<File> v = entry.getValue();
Collection<File> storedV = STORED.get(k);
if(storedV == null) {
// Another simple case -- key wasn't stored yet.
STORED.put(k, v);
} else {
synchronized(storedV) {
storedV.clear();
storedV.addAll(v);
}
}
}
}
}
}
/**
* Retrieves a set from the Container. If the object
* stored is not null or is not a set, a Set is inserted instead.
*
* The returned sets are synchronized, but the serialized sets are NOT SYNCHRONIZED.
* This means that the future can change what they synchronize on easily.
*/
synchronized Set<File> getSet(String name) {
Collection<File> data = STORED.get(name);
if (data != null) {
return (Set<File>)data;
} else {
Set<File> set = Collections.synchronizedSet(new HashSet<File>());
STORED.put(name, set);
return set;
}
}
/**
* Returns true if a Set by this name exists, false otherwise
*/
synchronized boolean contains(String name) {
Collection<File> data = STORED.get(name);
if(data == null)
return false;
else
return true;
}
/**
* Removes the set from the container.
* @param name - name of Set to remove
*/
synchronized void remove(String name) {
STORED.remove(name);
}
/**
* Clears all entries.
*/
synchronized void clear() {
for(Collection<File> data : STORED.values()) {
data.clear();
}
}
/**
* Saves the data to disk.
*/
void save() {
Map<String, Collection<File>> toSave;
synchronized(this) {
toSave = new HashMap<String, Collection<File>>(STORED.size());
for(Map.Entry<String, Collection<File>> entry : STORED.entrySet()) {
String k = entry.getKey();
Collection<File> v = entry.getValue();
synchronized(v) {
if(v instanceof SortedSet)
toSave.put(k, new TreeSet<File>((SortedSet<File>)v));
else if(v instanceof Set)
toSave.put(k, new HashSet<File>(v));
else if(v instanceof List) {
if (v instanceof RandomAccess)
toSave.put(k, new ArrayList<File>(v));
else
toSave.put(k, new LinkedList<File>(v));
} else {
if(LOG.isWarnEnabled())
LOG.warn("Update to clone! key: " + k);
toSave.put(k, v);
}
}
}
}
writeToDisk(toSave);
}
/**
* Saves the given object to disk.
*/
private void writeToDisk(Object o) {
File f = new File(CommonUtils.getUserSettingsDir(), filename);
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
oos.writeObject(o);
oos.flush();
} catch(IOException iox) {
LOG.warn("Can't write to disk!", iox);
} finally {
IOUtils.close(oos);
}
}
/**
* Reads a Map from disk.
*/
private Map<String, Collection<File>> readFromDisk() {
File file = new File(CommonUtils.getUserSettingsDir(), filename);
if (!file.exists()) {
return new HashMap<String, Collection<File>>();
}
ObjectInputStream ois = null;
Map map = null;
try {
ois = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)));
map = (Map)ois.readObject();
} catch(ClassCastException cce) {
LOG.warn("Not a map!", cce);
} catch(IOException iox) {
LOG.warn("Can't read from disk!", iox);
} catch(Throwable x) {
LOG.warn("Error reading!", x);
} finally {
IOUtils.close(ois);
}
if (map == null) {
return new HashMap<String, Collection<File>>();
}
HashMap<String, Collection<File>> toReturn = new HashMap<String, Collection<File>>(map.size());
for (Iterator i = map.entrySet().iterator(); i.hasNext();) {
Map.Entry entry = (Map.Entry)i.next();
if(!(entry.getKey() instanceof String)) {
if(LOG.isWarnEnabled())
LOG.warn("Ignoring key: " + entry.getKey());
continue;
}
String k = (String)entry.getKey();
if(!(entry.getValue() instanceof Collection)) {
if(LOG.isWarnEnabled())
LOG.warn("Ignoring value: " + entry.getValue());
continue;
}
Collection<File> v = GenericsUtils.scanForCollection(entry.getValue(), File.class,
GenericsUtils.ScanMode.REMOVE);
if(v instanceof SortedSet)
toReturn.put(k, Collections.synchronizedSortedSet((SortedSet<File>)v));
else if(v instanceof Set)
toReturn.put(k, Collections.synchronizedSet((Set<File>)v));
else if(v instanceof List)
toReturn.put(k, Collections.synchronizedList((List<File>)v));
else {
if(LOG.isWarnEnabled())
LOG.warn("Update to clone! key: " + k);
toReturn.put(k, v);
}
}
return toReturn;
}
}