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

com.almende.eve.state.file.FileStateBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.eve.state.file;

import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.almende.eve.capabilities.AbstractCapabilityBuilder;
import com.almende.eve.state.State;
import com.almende.eve.state.StateService;
import com.fasterxml.jackson.databind.node.ObjectNode;

/**
 * A factory for creating FileState objects.
 */
public class FileStateBuilder extends AbstractCapabilityBuilder {
	private static final Logger						LOG			= Logger.getLogger(FileStateBuilder.class
																		.getSimpleName());
	private static Map	instances	= new ConcurrentHashMap(10);
	
	@Override
	public State build() {
		final FileStateProvider provider = getInstanceByParams(getParams());
		if (provider != null) {
			return provider.get(getParams());
		} else {
			LOG.warning("Couldn't get FileStateProvider!");
			return null;
		}
	}
	
	/**
	 * Gets the instance by params.
	 * 
	 * @param params
	 *            the params
	 * @return the instance by params
	 */
	private FileStateProvider getInstanceByParams(final ObjectNode params) {
		
		final FileStateConfig config = new FileStateConfig(params);
		final String key = config.getPath();
		
		if (instances.containsKey(key)) {
			return instances.get(key);
		} else {
			synchronized (instances) {
				if (!instances.containsKey(key)) {
					final FileStateProvider result = new FileStateProvider(
							params);
					if (result != null) {
						instances.put(key, result);
					}
				}
				return instances.get(key);
			}
		}
	}
	
	class FileStateProvider implements StateService {
		private String						path		= null;
		private Boolean						json		= true;
		private Boolean						multilevel	= false;
		private final Map>	states		= new ConcurrentHashMap>(10);
		
		/**
		 * Instantiates a new file state provider.
		 * 
		 * @param params
		 *            the params
		 */
		public FileStateProvider(final ObjectNode params) {
			final FileStateConfig config = new FileStateConfig(params);
			json = config.getJson();
			setPath(config.getPath());
			
			if (params.has("multilevel")) {
				multilevel = params.get("multilevel").asBoolean();
			}
		}
		
		/**
		 * Instantiates a new file state provider.
		 * 
		 * @param path
		 *            the path
		 * @param json
		 *            the json
		 * @param multilevel
		 *            Whether the path contains a subdirectory for agent
		 *            categories.
		 */
		public FileStateProvider(final String path, final Boolean json,
				final Boolean multilevel) {
			this.json = json;
			this.multilevel = multilevel;
			setPath(path);
		}
		
		/**
		 * Instantiates a new file state factory.
		 * 
		 * @param path
		 *            the path
		 * @param json
		 *            the json
		 */
		public FileStateProvider(final String path, final Boolean json) {
			this.json = json;
			setPath(path);
		}
		
		/**
		 * Instantiates a new file state factory.
		 * 
		 * @param path
		 *            the path
		 */
		public FileStateProvider(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(final String path) {
			String actualPath = path;
			if (actualPath == null) {
				actualPath = ".eveagents";
				LOG.warning("Config parameter 'path' missing in State "
						+ "configuration. Using the default path '" + path
						+ "'");
			}
			if (!actualPath.endsWith("/")) {
				actualPath += "/";
			}
			this.path = actualPath;
			
			// make the directory
			final File file = new File(actualPath);
			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 += actualPath;
			}
			LOG.info(info
					+ ". "
					+ (json ? "(stored in JSON format)"
							: "(stored in JavaObject format)"));
		}
		
		/**
		 * Gets the.
		 * 
		 * @param params
		 *            the params
		 * @return the state
		 */
		public State get(final ObjectNode params) {
			final FileStateConfig config = new FileStateConfig(params);
			final String agentId = config.getId();
			if (agentId == null){
				LOG.warning("Parameter 'id' is required for a file State.");
				return null;
			}
			
			State state = null;
			try {
				if (!exists(agentId)) {
					final String filename = getFilename(agentId);
					final File file = new File(filename);
					
					file.createNewFile();
				}

				if (states.containsKey(agentId)) {
					WeakReference ref = states.get(agentId);
					if (ref != null){
						state = ref.get();
					}
				}
				if (state == null){
					if (json) {
						state = new ConcurrentJsonFileState(agentId,
								getFilename(agentId), this, params);
					} else {
						state = new ConcurrentSerializableFileState(
								agentId, getFilename(agentId), this, params);
					}
					states.put(agentId, new WeakReference(state));
				}
			} catch (IOException e) {
				LOG.log(Level.WARNING, "Couldn't create FileState", e);
			}
			return state;
		}
		
		/**
		 * Test if a state with given agentId exists.
		 * 
		 * @param agentId
		 *            the agent id
		 * @return true, if successful
		 */
		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 : "./";
			
			if (multilevel) {
				// 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
		 * com.almende.eve.state.StateService#delete(com.almende.eve.state.State)
		 */
		@Override
		public void delete(final State instance) {
			final String id = instance.getId();
			final File file = new File(getFilename(id));
			if (file.exists()) {
				file.delete();
			}
			states.remove(id);
		}
		
		/*
		 * (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();
		}

		@Override
		public Set getStateIds() {
			final File folder = new File(this.path);
			final File[] files = folder.listFiles();
			final List totalList = Arrays.asList(files);
			if (multilevel) {
				for (final File file : new ArrayList(totalList)) {
					if (!file.isDirectory()) {
						continue;
					}
					totalList.add(file);
				}
			}
			Set result = new HashSet(totalList.size());
			for (final File file : totalList){
				result.add(file.getName());
			}
			return result;
		}
	}
	
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy