All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almende.eve.state.ConcurrentFileState Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
package com.almende.eve.state;

import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

/**
 * @class FileState
 * 
 *        A persistent state for an Eve Agent, which stores the data on disk. 
 *        Data is stored in the path provided by the configuration file.
 * 
 *        The state provides general information for the agent (about itself,
 *        the environment, and the system configuration), and the agent can
 *        store its state in the state. The state extends a standard Java
 *        Map.
 * 
 *        All operations on this FileState are thread-safe. It also provides two
 *        aditional methods: PutIfNotChanged() and PutAllIfNotChanged().
 * 
 *        Usage:
* AgentFactory factory = new AgentFactory(config);
* ConcurrentFileState state = new * ConcurrentFileState("agentId",".eveagents");
* state.put("key", "value");
* System.out.println(state.get("key")); // "value"
* * @author jos * @author ludo */ public class ConcurrentFileState extends FileState { Logger logger = Logger.getLogger("ConcurrentFileState"); protected ConcurrentFileState() { } private String filename = null; private FileChannel channel = null; private FileLock lock = null; private InputStream fis = null; private OutputStream fos = null; private static List locked = new ArrayList(1); private static Map properties = Collections .synchronizedMap(new HashMap()); public ConcurrentFileState(String agentId, String filename) { super(agentId); this.filename = filename; if (locked.isEmpty()) locked.add(0,false); } @SuppressWarnings("resource") private void openFile() throws Exception { synchronized (locked) { while (locked.get(0)) { // logger.warning("Starting to wait for locked! "+filename); locked.wait(); } locked.set(0, true); File file = new File(this.filename); if (!file.exists()) throw new Exception("File doesn't exist (anymore):'"+this.filename+"'"); channel = new RandomAccessFile(file, "rw").getChannel(); // logger.warning("Locked set, starting to wait for fileLock! "+filename); lock = channel.lock(); // logger.warning("fileLock set! "+filename); fis = Channels.newInputStream(channel); fos = Channels.newOutputStream(channel); } } private void closeFile() { synchronized (locked) { if (channel != null && channel.isOpen()) { try{ lock.release(); // logger.warning("fileLock released! "+filename); fos.close(); fis.close(); channel.close(); } catch (Exception e){ e.printStackTrace(); } } channel = null; fis = null; fos = null; lock = null; locked.set(0, false); locked.notifyAll(); // logger.warning("locked released! "+filename); } } /** * write properties to disk * * @return success True if successfully written * @throws IOException */ private void write() throws Exception { channel.position(0); ObjectOutput out = new ObjectOutputStream(fos); out.writeObject(properties); out.flush(); } /** * read properties from disk * * @return success True if successfully read * @throws ClassNotFoundException * @throws IOException */ @SuppressWarnings("unchecked") private void read() throws Exception { try { channel.position(0); ObjectInput in = new ObjectInputStream(fis); properties.clear(); properties.putAll((Map) in.readObject()); } catch (EOFException eof){ //empty file, new agent? }; } /** * init is executed once before the agent method is invoked */ @Override public void init() { } /** * destroy is executed once after the agent method is invoked if the * properties are changed, they will be saved */ @Override public void destroy() {} @Override public synchronized void clear() { try { openFile(); properties.clear(); write(); } catch (Exception e) { e.printStackTrace(); } closeFile(); } @Override public synchronized Set keySet() { Set result = null; try { openFile(); read(); result = properties.keySet(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized boolean containsKey(Object key) { boolean result = false; try { openFile(); read(); result = properties.containsKey(key); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized boolean containsValue(Object value) { boolean result = false; try { openFile(); read(); result = properties.containsValue(value); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized Set> entrySet() { Set> result = null; try { openFile(); read(); result = properties.entrySet(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized Object get(Object key) { Object result = null; try { openFile(); read(); result = properties.get(key); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized boolean isEmpty() { boolean result = false; try { openFile(); read(); result = properties.isEmpty(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized Object put(String key, Object value) { Object result = null; try { openFile(); read(); result = properties.put(key, value); write(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized void putAll(Map map) { try { openFile(); read(); properties.putAll(map); write(); } catch (Exception e) { e.printStackTrace(); } closeFile(); } @Override public synchronized boolean putIfUnchanged(String key, Object newVal, Object oldVal) { boolean result=false; try { openFile(); read(); if (!(oldVal == null && properties.containsKey(key)) || properties.get(key).equals(oldVal)){ properties.put(key, newVal); write(); result=true; } } catch (Exception e){ e.printStackTrace(); } closeFile(); return result; } @Override public synchronized Object remove(Object key) { Object result = null; try { openFile(); read(); result = properties.remove(key); write(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized int size() { int result = -1; try { openFile(); read(); result = properties.size(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } @Override public synchronized Collection values() { Collection result = null; try { openFile(); read(); result = properties.values(); } catch (Exception e) { e.printStackTrace(); } closeFile(); return result; } }