1 /*********************************************************************
2 Copyright 2012, Ralph Ronnquist.
4 This file is part of GORITE.
6 GORITE is free software: you can redistribute it and/or modify it
7 under the terms of the Lesser GNU General Public License as published
8 by the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 GORITE is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the Lesser GNU General Public
17 License along with GORITE. If not, see <http://www.gnu.org/licenses/>.
18 **********************************************************************/
20 package com.intendico.gorite.addon;
22 import com.intendico.gorite.Performer;
23 import com.intendico.gorite.Data;
24 import com.intendico.gorite.Goal;
25 import com.intendico.gorite.BDIGoal;
26 import com.intendico.data.Query;
27 import com.intendico.data.Ref;
28 import com.intendico.data.Snapshot;
30 import java.util.IdentityHashMap;
31 import java.util.Observer;
32 import java.util.Vector;
33 import java.util.Iterator;
34 import java.util.Observable;
37 * A Reflector is a reasoning faculty to translate situation changes
38 * into percepts. The Reflector is populated with some number of
39 * {@link Reflection} objects, which each combines a {@link Query}
40 * with a {@link Goal}, so as to intend the {@link Goal} as a percept
41 * when the {@link Query} changes state, from false to true or from
42 * true to false, for particular bindings.
44 * <p> For example, consider the following code snippet:
46 * new Reflector( performer, "grandparent", "inference" ) {{
47 * Ref p = new Ref( "parent" );
48 * addQuery( new And( parent.get( new Ref( "gp"), p ),
49 * parent.get( p, new Ref( "ch") ) ) );
53 * The example code would keep observing the "parent" relation, and
54 * when it is updated to present a different grandparent-parent-child
55 * linkage from before, the goal "grandparent" is intended on the
56 * "inference" {@link com.intendico.gorite.Performer.TodoGroup
57 * Performer.TodoGroup}, with the data elements "gp", "parent" and
58 * "ch" set. Further, the data element "reflection event" is set to
59 * "added" or "lost" to indicate whether the change is of adding or
60 * losing a matching binding for the query.
63 * <p> Technicallly each added {@link Query} gets wrapped into a
64 * {@link Snapshot} in a {@link Reflector.Reflection} object, which is
65 * set up as {@link Observer} to observe any changes to the {@link
66 * Query} sources. The {@link Snapshot} wrapping acts as a filter to
67 * ensure that only changes cause percepts. The percept will hold the
68 * input query as "percept" data element, and all {@link Ref} object
69 * values of the query as corresponding data elemens.
72 public class Reflector extends Perceptor {
75 * The name of the data element to indicate whether its an
78 public String REFLECTION_EVENT = "reflection event";
81 * Constructor that ties the Reflector to the given {@link
82 * Performer}, causing goals as named in the {@link
83 * com.intendico.gorite.Performer.TodoGroup Performer.TodoGroup}
86 public Reflector(Performer p,String goal,String todo) {
87 super( p, goal, todo );
91 * Utility class for observing the query sources, and trigger
92 * goals when bindings change state.
94 public class Reflection implements Observer {
97 * Holds the query wrapped into a {@link Snapshot}
102 * Holds the perception goal caused by this reflection.
107 * Holds the reflection mode; postive for reacting to added
108 * bindings, negative for reacting to lost bindings and zero
114 * Alternative constructor, with a goal name.
116 public Reflection(Query q,String g) {
117 this( q, g != null? new BDIGoal( g ) : null );
121 * Constructor, which applies the {@link Snapshot} wrapping.
123 public Reflection(Query q,Goal g) {
124 snap = new Snapshot( q );
125 snap.addObserver( this );
130 * Implements {@link Observer#update} by reviewing the query
131 * and generating percepts for new bindings.
133 synchronized public void update(Observable x,Object y) {
136 Vector/*<Ref>*/ refs = snap.getRefs( new Vector/*<Ref>*/() );
138 // Process added bindings
139 while ( snap.next() ) {
142 d.setValue( REFLECTION_EVENT, "added" );
143 perceive( snap.query, d, goal );
147 // Process lost bindings
148 for ( Iterator/*<Vector>*/ i =
149 snap.lost.iterator(); i.hasNext(); ) {
150 Vector v = (Vector) i.next();
154 d.setValue( REFLECTION_EVENT, "lost" );
155 perceive( snap.query, d, goal );
158 } catch (Exception e) {
164 * Cancels the observation of query sources.
166 public void cancel() {
167 snap.deleteObserver( this );
172 * Keeps the current collection of queries, which are contained in
173 * {@link Reflection} objects
175 public IdentityHashMap/*<Query,Reflection>*/ reflections =
176 new IdentityHashMap/*<Query,Reflection>*/();
179 * Adds a {@link Reflection} that uses the given {@link Query}.
181 public void addQuery(Query q) {
182 addQuery( q, (String) null );
186 * Adds a {@link Reflection} query using the given {@link
189 public void addQuery(Query q,String goal) {
190 addQuery( q, goal, 1 );
194 * Adds a {@link Reflection} query using the given {@link
197 public void addQuery(Query q,String goal,int m) {
198 Reflection r = (Reflection) reflections.get( q );
200 r = new Reflection( q, goal );
202 reflections.put( q, r );
203 r.update( null, null );
204 } else if ( r.mode != m ) {
206 r.update( null, null );
211 * Adds a reflection query using the given Reflection goal.
213 public void addQuery(Query q,Goal goal) {
214 addQuery( q, goal, 1 );
218 * Adds a reflection query using the given Reflection goal.
220 public void addQuery(Query q,Goal goal,int m) {
221 Reflection r = (Reflection) reflections.get( q );
223 r = new Reflection( q, goal );
225 reflections.put( q, r );
226 r.update( null, null );
227 } else if ( r.mode != m ) {
229 r.update( null, null );
234 * Removes the {@link Reflection} that uses the given {@link
237 public void removeQuery(Query q) {
238 Reflection r = (Reflection) reflections.remove( q );
245 * Returns a String representation of this object.
247 public String toString() {
248 StringBuilder s = new StringBuilder();
249 s.append( "Reflector(" + performer + "," +
250 handler + ",\"" + todo_group + "\"):" );
251 for ( Iterator/*<Query>*/ ri = reflections.keySet().iterator();
253 Query q = (Query) ri.next();
254 s.append( "\n query: " );
255 s.append( q.toString() );