1/*****************************************************************************
    2 * This file is part of the Prolog Development Tool (PDT)
    3 * 
    4 * Author: Lukas Degener (among others)
    5 * WWW: http://sewiki.iai.uni-bonn.de/research/pdt/start
    6 * Mail: pdt@lists.iai.uni-bonn.de
    7 * Copyright (C): 2004-2012, CS Dept. III, University of Bonn
    8 * 
    9 * All rights reserved. This program is  made available under the terms
   10 * of the Eclipse Public License v1.0 which accompanies this distribution,
   11 * and is available at http://www.eclipse.org/legal/epl-v10.html
   12 * 
   13 ****************************************************************************/
   14
   15:- if(\+ current_module(process_observe)).   16
   17:- module(process_observe,[
   18	process_observe/3,
   19	process_observe/2,	
   20	process_unobserve/2,
   21	process_notify/2,
   22	process_dispatch/3
   23]).   24
   25:- use_module(library(debug)).   26
   27/*
   28 * to activate debugging for this module, uncomment:
   29 */
   30:- debug(process_observe).   31
   32:-dynamic process_observe_hook/3,process_unobserve_hook/3.   33:-multifile process_observe_hook/3,process_unobserve_hook/3.   34
   35% process_observe_hook(Thread,Subject,Key),
   36% A hook predicate that will be called each time an observer registers to 
   37% a subject, if it is not already registered with this subject.
   38% Clients that provide observable subjects can add clauses to these predicates
   39% if they need to take additional actions on registration of an observer
   40% to a subject. If the call succeeds, it is assumes that these additional actions have 
   41% been taken.
   42% 
   43process_observe_hook(_,_,_):-
   44	fail.	     	
   45
   46% process_unobserve_hook(Thread,Subject,Key),
   47% A hook predicate that will be called each time an observer unregisters to 
   48% a subject. see process_observe_hook/3
   49% 
   50process_unobserve_hook(_,_,_):-
   51	fail.	     	
   52
   53call_observe_hook(Thread,Subject,Key):-
   54	catch(process_observe_hook(Thread,Subject,Key),E,print_message(error,E)),
   55	!.  
   56call_observe_hook(_,_,_).
   57call_unobserve_hook(Thread,Subject,Key):-
   58	catch(process_unobserve_hook(Thread,Subject,Key),E,print_message(error,E)),
   59	!.  		
   60call_unobserve_hook(_,_,_).	
   61
   62
   63/*
   64 * backwards compatibility. 
   65 */
   66process_observe(Thread,Subject):-
   67   term_to_atom(Subject,Key),
   68   process_observe(Thread,Subject,Key). 
 process_observe(+Thread, +Subject)
Add an observer to a subject.
Arguments:
Thread- the observer, i.e. a thread that is running dispatch/3
Subject- the subject to observe. This term is unified with the subject given as second argument to notify/2.
Key- should be an atom. During notification, if the Subject terms was successfully unified, the key is also passed to the observer. The idea of this is to help observers calling from Java, or otherwise lacking the concept of unification, to recognize the Subject they subscribed for.
   82process_observe(Thread,Subject,Key) :-
   83  recorded(process_observer,observation(Thread,OtherSubject,Key), _),
   84  OtherSubject =@= Subject,
   85  !.
   86
   87process_observe(Thread,Subject,Key) :-
   88%  sync:init_idb(Subject),
   89  call_observe_hook(Thread,Subject,Key),
   90  recordz(process_observer,observation(Thread,Subject,Key), _).
 process_unobserve(+Thread, +Subject)
Remove an observer from a subject.
Arguments:
Thread- the observer thread to remove.
Subject- the subject from which to remove the observer.
  101process_unobserve(Thread,Subject) :-
  102  recorded(process_observer,observation(Thread,OtherSubject,Key),Ref),
  103  OtherSubject =@= Subject,
  104  erase(Ref),
  105  %sync:unregister_observer(Subject). 
  106  call_unobserve_hook(Thread,Subject,Key).
 process_notify(+Subject, +Event)
Notify all active observers. If observer's thread is stopped it will be removed.
  113process_notify(Subject,Event) :-
  114   debug(process_observe,'~w~n',[process_notify(Subject,Event)]),
  115   forall(
  116    	( 
  117    	  recorded(process_observer,observation(Thread,Subject,_),Ref)
  118    	),
  119    	(	current_thread(Thread,running)
  120    	->	(    	      
  121    	      thread_send_message(Thread,notify(Subject,Event)),
  122   	      debug(process_observe,'~w~n',[thread_send_message(Thread,notify(Subject,Event))])
  123    	   
  124    	);	erase(Ref)
  125    	)
  126    ).   
 process_dispatch(-Subject, -Key, -Event)
Recieve events. This predicate is intended to be called by observer threads. It produces solutions for every recieved event, i.e. every time process_notify/2 is called on a subject the observer thread is subscribed for. If it recieves an event for the subject '$stop' it will cut and fail.
  136 process_dispatch(Subject,Key,Event):-
  137     	thread_self(Me),
  138     	repeat,
  139	     	thread_get_message(notify(Subject,Event)),
  140	     	(	Subject='$abort'
  141	     	->	!
  142	     	;	recorded(process_observer,observation(Me,Subject,Key), _)
  143	     	).
  144	     	
  145	     	
  146
  147:- endif.