/****************************************************************************** * * Copyright 2014 Paphus Solutions Inc. * * Licensed under the Eclipse Public License, Version 1.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ package org.botlibre.thought; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; import org.botlibre.api.knowledge.MemoryEventListener; import org.botlibre.api.knowledge.Network; import org.botlibre.api.knowledge.Vertex; import org.botlibre.knowledge.Primitive; import org.botlibre.thought.BasicThought; /** * A sub-conscious thought that processes active memory in the background. */ public abstract class SubconsciousThought extends BasicThought { public int threshold = 200; public int delay = 0; protected Queue<Vertex> activeMemoryBackLog = new ConcurrentLinkedQueue<Vertex>(); protected MemoryEventListener listener; public SubconsciousThought() { } /** * Determine if the thought should first wait for conscious thoughts to process the input. */ public boolean isConsciousProcessingRequired() { return false; } /** * Add a listener to the memory to be notified when new active memory. */ @Override public void awake() { super.awake(); this.listener = new MemoryEventListener() { public void addActiveMemory(Vertex vertex) { if (isStopped || !isEnabled || !bot.mind().isConscious()) { return; } if (getActiveMemoryBackLog().size() > SubconsciousThought.this.threshold) { bot.log(this, "Subconscious backlog threshold reached, clearing backlog", Level.WARNING); getActiveMemoryBackLog().clear(); } getActiveMemoryBackLog().add(vertex); } }; this.bot.memory().addListener(this.listener); } public void stop() { super.stop(); this.bot.memory().removeListener(this.listener); } /** * Analyze the active memory. * Output the active article to the senses. */ @Override public void think() { if (this.isStopped || !this.isEnabled || !this.bot.mind().isConscious()) { getActiveMemoryBackLog().clear(); return; } Vertex vertex = getActiveMemoryBackLog().poll(); if (vertex != null) { try { Thread.sleep(this.delay); if (this.isStopped || !this.isEnabled || !this.bot.mind().isConscious()) { getActiveMemoryBackLog().clear(); return; } Network memory = this.bot.memory().newMemory(); vertex = memory.createVertex(vertex); int abort = 0; if (isConsciousProcessingRequired()) { while ((abort < 20) && !vertex.hasRelationship(Primitive.CONTEXT)) { Thread.sleep(1000); if (this.isStopped || !this.isEnabled || !this.bot.mind().isConscious()) { getActiveMemoryBackLog().clear(); return; } memory = this.bot.memory().newMemory(); vertex = memory.createVertex(vertex); abort++; } } if (abort < 20) { boolean commit = processInput(vertex, memory); if (commit && isEnabled() && !isStopped() && this.bot.mind().isConscious()) { memory.save(); } } } catch (Exception failed) { log(failed); } } } /** * Process the active memory in the isolated memory in the background. * Return if memory should be saved, or discarded. */ public abstract boolean processInput(Vertex vertex, Network network); /** * Thoughts can be conscious or sub-conscious. * A conscious thought is run by the mind single threaded with exclusive access to the short term memory. * A sub-conscious thought is run concurrently, and must run in its own memory space. */ @Override public boolean isConscious() { return false; } public Queue<Vertex> getActiveMemoryBackLog() { return activeMemoryBackLog; } public void setActiveMemoryBackLog(Queue<Vertex> activeMemoryBackLog) { this.activeMemoryBackLog = activeMemoryBackLog; } }