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

org.structr.agent.AgentService Maven / Gradle / Ivy

Go to download

Structr is an open source framework based on the popular Neo4j graph database.

The newest version!
/**
 * Copyright (C) 2010-2016 Structr GmbH
 *
 * This file is part of Structr .
 *
 * Structr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * Structr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Structr.  If not, see .
 */
package org.structr.agent;

import org.structr.api.service.Command;
import org.structr.api.service.RunnableService;
import org.structr.core.Services;

//~--- JDK imports ------------------------------------------------------------

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.structr.api.service.StructrServices;
import org.structr.schema.ConfigurationProvider;

//~--- classes ----------------------------------------------------------------

/**
 * The agent service main class.
 *
 *
 */
public class AgentService extends Thread implements RunnableService {

	private static final Logger logger = Logger.getLogger(AgentService.class.getName());

	//~--- fields ---------------------------------------------------------

	private final int maxAgents                          = 4;    // TODO: make configurable
	private final Map> runningAgents = new ConcurrentHashMap<>(10, 0.9f, 8);
	private final Map agentClassCache     = new ConcurrentHashMap<>(10, 0.9f, 8);
	private final Queue taskQueue                  = new ConcurrentLinkedQueue<>();
	private Set supportedCommands                 = null;
	private boolean run                                  = false;

	//~--- constructors ---------------------------------------------------

	public AgentService() {

		super("AgentService");
		supportedCommands = new LinkedHashSet<>();
		supportedCommands.add(ProcessTaskCommand.class);

		super.setDaemon(true);
	}

	//~--- methods --------------------------------------------------------

	public void processTask(Task task) {

		synchronized (taskQueue) {

			taskQueue.add(task);
			logger.log(Level.FINE, "Task {0} added to task queue", task);
		}
	}

	public Agent findAgentForTask(Task task) {

		List agents = getRunningAgentsForTask(task.getClass());

		synchronized (agents) {

			for (Agent agent : agents) {

				if (agent.getTaskQueue().contains(task)) {
					return (agent);
				}
			}
		}

		return (null);
	}

	@Override
	public void run() {

		logger.log(Level.INFO, "AgentService started");

		while (run) {

			Task nextTask = taskQueue.poll();
			if (nextTask != null) {

				assignNextAgentForTask(nextTask);
			}

			// let others act
			try { Thread.sleep(10); } catch(Throwable ignore) {}
		}
	}

	public void notifyAgentStart(Agent agent) {

		List agents = getRunningAgentsForTask(agent.getSupportedTaskType());

		synchronized (agents) {
			agents.add(agent);
		}
	}

	public void notifyAgentStop(Agent agent) {

		List agents = getRunningAgentsForTask(agent.getSupportedTaskType());

		synchronized (agents) {
			agents.remove(agent);
		}
	}

	public Map> getAgents() {

		final ConfigurationProvider configuration = Services.getInstance().getConfigurationProvider();
		if (configuration != null) {

			return configuration.getAgents();
		}

		return Collections.emptyMap();
	}

	// 
	@Override
	public void injectArguments(Command command) {
		command.setArgument("agentService", this);
	}

	@Override
	public void initialize(final StructrServices services, final Properties config) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
	}

	@Override
	public void initialized() {}

	@Override
	public void shutdown() {}

	@Override
	public void startService() {

		run = true;
		this.start();
	}

	@Override
	public void stopService() {
		run = false;
	}

	@Override
	public boolean runOnStartup() {
		return (true);
	}

	// 

	// 
	private void assignNextAgentForTask(Task nextTask) {

		Class taskClass    = nextTask.getClass();
		List agents = getRunningAgentsForTask(taskClass);

		// need to synchronize on agents
		synchronized (agents) {

			// find next free agent (agents should be sorted by load, so one
			// of the first should do..
			for (Agent agent : agents) {

				if (agent.assignTask(nextTask)) {

					// ok, task is assigned
					logger.log(Level.FINE, "Task assigned to agent {0}", agent.getName());

					return;
				}
			}
		}

		// FIXME: find better solution for hard limit here!
		if (agents.size() < maxAgents) {

			// if we get here, task was not assigned to any agent, need to
			// create a new one.
			Agent agent = createAgent(nextTask);

			if ((agent != null) && agent.assignTask(nextTask)) {
				agent.start();
			} else {

				// re-add task..
				synchronized (taskQueue) {
					taskQueue.add(nextTask);
				}
			}
		} else {

			logger.log(Level.FINE, "Overall agents limit reached, re-queueing task");

			// re-add task..
			synchronized (taskQueue) {
				taskQueue.add(nextTask);
			}
		}
	}

	/**
	 * Creates a new agent for the given Task. Note that the agent must be
	 * started manually after creation.
	 *
	 * @param forTask
	 * @return a new agent for the given task
	 */
	private Agent createAgent(Task forTask) {

		Agent agent = null;

		try {

			agent = lookupAgent(forTask);

			if (agent != null) {

				// register us in agent..
				agent.setAgentService(this);
			}

		} catch (Exception ex) {

			// TODO: handle exception etc..
		}

		return (agent);
	}

	private Agent lookupAgent(Task task) {

		// FIXME: superuser security context
		Class taskClass  = task.getClass();
		Agent agent      = null;
		Class agentClass = agentClassCache.get(taskClass.getName());

		// cache miss
		if (agentClass == null) {

			Map> agentClassesMap = getAgents();

			if (agentClassesMap != null) {

				for (Entry> classEntry : agentClassesMap.entrySet()) {

					Class supportedAgentClass = agentClassesMap.get(classEntry.getKey());

					try {

						Agent supportedAgent     = supportedAgentClass.newInstance();
						Class supportedTaskClass = supportedAgent.getSupportedTaskType();

						if (supportedTaskClass.equals(taskClass)) {
							agentClass = supportedAgentClass;
						}

						agentClassCache.put(supportedTaskClass.getName(), supportedAgentClass);

					} catch (Throwable ignore) {}
				}
			}
		}

		if (agentClass != null) {

			try {
				agent = (Agent) agentClass.newInstance();

			} catch (Throwable ignore) {}
		}

		return (agent);
	}

	// 

	//~--- get methods ----------------------------------------------------

	/**
	 * Returns the current queue of remaining tasks.
	 * @return tasks
	 */
	public Collection getTaskQueue() {
		return (taskQueue);
	}

	/**
	 * Returns the current collection of running agents.
	 * @return agents
	 */
	public Map> getRunningAgents() {
		return (runningAgents);
	}

	private List getRunningAgentsForTask(Class taskClass) {

		List agents = runningAgents.get(taskClass.getName());

		if (agents == null) {

			agents = Collections.synchronizedList(new LinkedList());

			// Hashtable is synchronized
			runningAgents.put(taskClass.getName(), agents);
		}

		return (agents);
	}

	@Override
	public boolean isRunning() {
		return (this.run);
	}

	@Override
	public boolean isVital() {
		return false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy