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

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

There is a newer version: 3.1.1
Show newest version
/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.eve.state;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

/**
 * A factory for creating FileState objects.
 */
public class FileStateFactory implements StateFactory {
	private static final Logger			LOG		= Logger.getLogger(FileStateFactory.class
														.getSimpleName());
	private String						path	= null;
	private Boolean						json	= false;
	private final Map	states	= new HashMap();
	
	/**
	 * This constructor is called when constructed by the AgentHost.
	 * 
	 * @param params
	 *            the params
	 */
	public FileStateFactory(Map params) {
		// built the path where the agents will be stored
		if (params == null) {
			params = new HashMap();
		}
		if (params.containsKey("json")) {
			json = (Boolean) params.get("json");
		}
		
		if (params.containsKey("path")) {
			setPath((String) params.get("path"));
		}
	}
	
	/**
	 * Instantiates a new file state factory.
	 * 
	 * @param path
	 *            the path
	 * @param json
	 *            the json
	 */
	public FileStateFactory(final String path, final Boolean json) {
		this.json = json;
		setPath(path);
	}
	
	/**
	 * Instantiates a new file state factory.
	 * 
	 * @param path
	 *            the path
	 */
	public FileStateFactory(final String path) {
		this(path, false);
	}
	
	/**
	 * Set the path where the agents data will be stored.
	 * 
	 * @param path
	 *            the new path
	 */
	private synchronized void setPath(String path) {
		if (path == null) {
			path = ".eveagents";
			LOG.warning("Config parameter 'state.path' missing in Eve "
					+ "configuration. Using the default path '" + path + "'");
		}
		if (!path.endsWith("/")) {
			path += "/";
		}
		this.path = path;
		
		// make the directory
		final File file = new File(path);
		if (!file.exists() && !file.mkdir()) {
			LOG.severe("Could not create State folder!");
			throw new IllegalStateException();
		}
		
		// log info
		String info = "Agents will be stored in ";
		try {
			info += file.getCanonicalPath();
		} catch (final IOException e) {
			info += path;
		}
		LOG.info(info
				+ ". "
				+ (json ? "(stored in JSON format)"
						: "(stored in JavaObject format)"));
	}
	
	/**
	 * Get state with given id. Will return null if not found
	 * 
	 * @param agentId
	 *            the agent id
	 * @param json
	 *            the json
	 * @return state
	 */
	public State get(final String agentId, final boolean json) {
		State state = null;
		if (exists(agentId)) {
			if (states.containsKey(agentId)) {
				state = states.get(agentId);
			} else {
				if (json) {
					state = new ConcurrentJsonFileState(agentId,
							getFilename(agentId));
				} else {
					state = new ConcurrentSerializableFileState(agentId,
							getFilename(agentId));
				}
				states.put(agentId, state);
			}
		}
		return state;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.state.StateFactory#get(java.lang.String)
	 */
	@Override
	public State get(final String agentId) {
		return get(agentId, json);
	}
	
	/**
	 * Create a state with given id. Will throw an exception when already.
	 * existing.
	 * 
	 * @param agentId
	 *            the agent id
	 * @param json
	 *            the json
	 * @return state
	 * @throws IOException
	 *             Signals that an I/O exception has occurred.
	 */
	public synchronized State create(final String agentId, final boolean json)
			throws IOException {
		if (exists(agentId)) {
			throw new IllegalStateException("Cannot create state, "
					+ "state with id '" + agentId + "' already exists.");
		}
		
		// store the new (empty) file
		// TODO: it is not so nice solution to create an empty file to mark the
		// state as created.
		final String filename = getFilename(agentId);
		final File file = new File(filename);
		file.createNewFile();
		
		State state = null;
		// instantiate the state
		if (json) {
			state = new ConcurrentJsonFileState(agentId, filename);
		} else {
			state = new ConcurrentSerializableFileState(agentId, filename);
		}
		states.put(agentId, state);
		return state;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.state.StateFactory#create(java.lang.String)
	 */
	@Override
	public synchronized State create(final String agentId) throws IOException {
		return create(agentId, json);
	}
	
	/**
	 * Delete a state. If the state does not exist, nothing will happen.
	 * 
	 * @param agentId
	 *            the agent id
	 */
	@Override
	public void delete(final String agentId) {
		final File file = new File(getFilename(agentId));
		if (file.exists()) {
			file.delete();
		}
		states.remove(agentId);
	}
	
	/**
	 * Test if a state with given agentId exists.
	 * 
	 * @param agentId
	 *            the agent id
	 * @return true, if successful
	 */
	@Override
	public boolean exists(final String agentId) {
		final File file = new File(getFilename(agentId));
		return file.exists();
	}
	
	/**
	 * Get the filename of the saved.
	 * 
	 * @param agentId
	 *            the agent id
	 * @return the filename
	 */
	private String getFilename(final String agentId) {
		
		final String apath = path != null ? path : "./";
		
		// try 1 level of subdirs. I need this badly, tymon
		final File folder = new File(apath);
		final File[] files = folder.listFiles();
		final List totalList = Arrays.asList(files);
		for (final File file : totalList) {
			if (!file.isDirectory()) {
				continue;
			}
			final String ret = apath + file.getName() + "/" + agentId;
			if (new File(ret).exists()) {
				return ret;
			}
		}
		
		return apath + agentId;
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		final Map data = new HashMap();
		data.put("class", this.getClass().getName());
		data.put("path", path);
		return data.toString();
	}
	
	/*
	 * (non-Javadoc)
	 * 
	 * @see com.almende.eve.state.StateFactory#getAllAgentIds()
	 */
	@Override
	public Iterator getAllAgentIds() {
		final File folder = new File(path);
		File[] files = folder.listFiles();
		if (files == null) {
			files = new File[0];
		}
		final List list = new ArrayList(files.length);
		
		if (files.length > 0) {
			final List totalList = Arrays.asList(files);
			for (final File file : totalList) {
				if (file.isFile() && file.canRead() && !file.isHidden()
						&& file.length() > 2) {
					list.add(file);
				}
				
				// try 1 level of subdirs. i need this badly, tymon
				if (file.isDirectory() && file.canRead()) {
					final File folder2 = new File(path + file.getName());
					final File[] files2 = folder2.listFiles();
					final List totalList2 = Arrays.asList(files2);
					for (final File file2 : totalList2) {
						if (file2.isFile() && file2.canRead()) {
							list.add(file2);
						}
					}
				}
				
			}
		}
		return new Iterator() {
			private int	pivot	= 0;
			
			@Override
			public boolean hasNext() {
				return pivot < list.size();
			}
			
			@Override
			public String next() {
				return (list.get(pivot++).getName());
			}
			
			@Override
			public void remove() {
				list.remove(pivot);
			}
		};
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy