package org.jboss.cache.loader;
import org.jboss.cache.TreeCache;
import org.jboss.cache.Fqn;
import org.jboss.cache.Modification;
import org.jboss.logging.Logger;
import org.jboss.invocation.MarshalledValueInputStream;
import org.jboss.invocation.MarshalledValueOutputStream;
import java.util.*;
import java.io.*;
public class FileCacheLoader implements CacheLoader {
File root=null;
TreeCache cache=null;
Logger log=Logger.getLogger(getClass());
HashMap transactions=new HashMap();
public static final String DATA="data.dat";
public static final String DIR_SUFFIX="fdb";
public FileCacheLoader() {
}
public void setConfig(Properties props) {
String location=props != null? props.getProperty("location") : null;
root=new File(location);
}
public void setCache(TreeCache c) {
cache=c;
}
public void create() throws Exception {
if(!root.exists())
throw new FileNotFoundException(root.toString());
}
public void start() throws Exception {
}
public void stop() {
}
public void destroy() {
}
public Set getChildrenNames(Fqn fqn) throws Exception {
File parent=getDirectory(fqn, false);
if(parent == null) return null;
File[] children=parent.listFiles();
HashSet s=new HashSet();
for(int i=0; i < children.length; i++) {
File child=children[i];
if(child.isDirectory() && child.getName().endsWith(DIR_SUFFIX)) {
String child_name=child.getName();
child_name=child_name.substring(0, child_name.lastIndexOf(DIR_SUFFIX)-1);
s.add(child_name);
}
}
return s.size() == 0? null : s;
}
public Object get(Fqn fqn, Object key) throws Exception {
Map m=loadAttributes(fqn);
if(m == null) return null;
return m.get(key);
}
public Map get(Fqn fqn) throws Exception {
Map m=loadAttributes(fqn);
if(m == null || m.size() == 0) return null;
return m;
}
public boolean exists(Fqn fqn) throws Exception {
File f=getDirectory(fqn, false);
return f != null;
}
public Object put(Fqn fqn, Object key, Object value) throws Exception {
Object retval=null;
Map m=loadAttributes(fqn);
if(m == null) m=new HashMap();
retval=m.put(key, value);
storeAttributes(fqn, m);
return retval;
}
public void put(Fqn fqn, Map attributes) throws Exception {
put(fqn, attributes, false);
}
public void put(Fqn fqn, Map attributes, boolean erase) throws Exception {
Map m=erase? new HashMap() : loadAttributes(fqn);
if(m == null) m=new HashMap();
if(attributes != null)
m.putAll(attributes);
storeAttributes(fqn, m);
}
private void put(Fqn fqn) throws Exception {
getDirectory(fqn, true);
}
public void put(List modifications) throws Exception {
if(modifications == null) return;
for(Iterator it=modifications.iterator(); it.hasNext();) {
Modification m=(Modification)it.next();
switch(m.getType()) {
case Modification.PUT_DATA:
put(m.getFqn(), m.getData());
break;
case Modification.PUT_DATA_ERASE:
put(m.getFqn(), m.getData(), true);
break;
case Modification.PUT_KEY_VALUE:
put(m.getFqn(), m.getKey(), m.getValue());
break;
case Modification.REMOVE_DATA:
removeData(m.getFqn());
break;
case Modification.REMOVE_KEY_VALUE:
remove(m.getFqn(), m.getKey());
break;
case Modification.REMOVE_NODE:
remove(m.getFqn());
break;
default:
log.error("modification type " + m.getType() + " not known");
break;
}
}
}
public Object remove(Fqn fqn, Object key) throws Exception {
Object retval=null;
Map m=loadAttributes(fqn);
if(m == null) return null;
retval=m.remove(key);
storeAttributes(fqn, m);
return retval;
}
public void remove(Fqn fqn) throws Exception {
File dir=getDirectory(fqn, false);
if(dir != null) {
boolean flag=removeDirectory(dir, true);
if(flag == false)
log.warn("failed removing " + fqn);
}
}
public void removeData(Fqn fqn) throws Exception {
File f=getDirectory(fqn, false);
if(f != null) {
File data=new File(f, DATA);
if(data != null && data.exists()) {
boolean flag=data.delete();
if(!flag)
log.warn("failed removing file " + data.getName());
}
}
}
public void prepare(Object tx, List modifications, boolean one_phase) throws Exception {
if(one_phase)
put(modifications);
else
transactions.put(tx, modifications);
}
public void commit(Object tx) throws Exception {
List modifications=(List)transactions.get(tx);
if(modifications == null)
throw new Exception("transaction " + tx + " not found in transaction table");
put(modifications);
transactions.remove(tx);
}
public void rollback(Object tx) {
transactions.remove(tx);
}
public byte[] loadEntireState() throws Exception {
ByteArrayOutputStream out_stream=new ByteArrayOutputStream(1024);
ObjectOutputStream out=new MarshalledValueOutputStream(out_stream);
loadStateFromFilessystem(Fqn.fromString("/"), out);
out.close();
return out_stream.toByteArray();
}
public void storeEntireState(byte[] state) throws Exception {
ByteArrayInputStream in_stream=new ByteArrayInputStream(state);
MarshalledValueInputStream in=new MarshalledValueInputStream(in_stream);
NodeData nd;
this.remove(Fqn.fromString("/"));
try {
while(true) {
nd=(NodeData)in.readObject();
if(nd.attrs != null)
this.put(nd.fqn, nd.attrs, true); else
this.put(nd.fqn); }
}
catch(EOFException eof_ex) {
;
}
}
void loadStateFromFilessystem(Fqn fqn, ObjectOutputStream out) throws Exception {
Map attrs;
Set children_names;
String child_name;
Fqn tmp_fqn;
NodeData nd;
attrs=get(fqn);
if(attrs == null || attrs.size() == 0)
nd=new NodeData(fqn);
else
nd=new NodeData(fqn, attrs);
out.writeObject(nd);
children_names=getChildrenNames(fqn);
if(children_names == null)
return;
for(Iterator it=children_names.iterator(); it.hasNext();) {
child_name=(String)it.next();
tmp_fqn=new Fqn(fqn, child_name);
loadStateFromFilessystem(tmp_fqn, out);
}
}
File getDirectory(Fqn fqn, boolean create) {
File f=new File(getFullPath(fqn));
if(!f.exists()) {
if(create)
f.mkdirs();
else
return null;
}
return f;
}
boolean removeDirectory(File dir, boolean include_start_dir) {
boolean success=true;
File[] subdirs=dir.listFiles();
for(int i=0; i < subdirs.length; i++) {
File file=subdirs[i];
if(file.isFile() && file.getName().equals(DATA)) {
if(file.delete() == false)
success=false;
continue;
}
if(file.isDirectory() && file.getName().endsWith(DIR_SUFFIX)) {
if(removeDirectory(file, false) == false)
success=false;
if(file.delete() == false)
success=false;
}
}
if(include_start_dir) {
if(dir.equals(root)) {
;
}
else {
if(dir.delete() == false)
success=false;
}
}
return success;
}
String getFullPath(Fqn fqn) {
StringBuffer sb=new StringBuffer(root.getAbsolutePath() + File.separator);
for(int i=0; i < fqn.size(); i++) {
Object tmp=fqn.get(i);
String tmp_dir;
if(tmp instanceof String)
tmp_dir=(String)tmp;
else
tmp_dir=tmp.toString();
sb.append(tmp_dir).append(".").append(DIR_SUFFIX).append(File.separator);
}
return sb.toString();
}
Map loadAttributes(Fqn fqn) throws Exception {
File f=getDirectory(fqn, false);
if(f == null) return null;
File child=new File(f, DATA);
if(!child.exists()) return null;
FileInputStream in=new FileInputStream(child);
MarshalledValueInputStream input=new MarshalledValueInputStream(in);
Map m=(Map)input.readObject();
in.close();
return m;
}
void storeAttributes(Fqn fqn, Map attrs) throws Exception {
File f=getDirectory(fqn, true);
File child=new File(f, DATA);
if(!child.exists())
child.createNewFile();
FileOutputStream out=new FileOutputStream(child);
ObjectOutputStream output=new ObjectOutputStream(out);
output.writeObject(attrs);
out.close();
}
}