1102 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
		
		
			
		
	
	
			1102 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| 
								 | 
							
								/*  $Id$
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Part of SWI-Prolog
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Author:        Jan Wielemaker
							 | 
						||
| 
								 | 
							
								    E-mail:        wielemak@science.uva.nl
							 | 
						||
| 
								 | 
							
								    WWW:           http://www.swi-prolog.org
							 | 
						||
| 
								 | 
							
								    Copyright (C): 1985-2007, University of Amsterdam
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This program 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 2
							 | 
						||
| 
								 | 
							
								    of the License, or (at your option) any later version.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This program 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 Lesser General Public
							 | 
						||
| 
								 | 
							
								    License along with this library; if not, write to the Free Software
							 | 
						||
| 
								 | 
							
								    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    As a special exception, if you link this library with other files,
							 | 
						||
| 
								 | 
							
								    compiled with a Free Software compiler, to produce an executable, this
							 | 
						||
| 
								 | 
							
								    library does not by itself cause the resulting executable to be covered
							 | 
						||
| 
								 | 
							
								    by the GNU General Public License. This exception does not however
							 | 
						||
| 
								 | 
							
								    invalidate any other reasons why the executable file might be covered by
							 | 
						||
| 
								 | 
							
								    the GNU General Public License.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- module(rdf_edit,
							 | 
						||
| 
								 | 
							
									  [ rdfe_assert/3,		% Sub, Pred, Obj
							 | 
						||
| 
								 | 
							
									    rdfe_assert/4,		% Sub, Pred, Obj, PayLoad
							 | 
						||
| 
								 | 
							
									    rdfe_retractall/3,		% Sub, Pred, Obj
							 | 
						||
| 
								 | 
							
									    rdfe_retractall/4,		% Sub, Pred, Obj, PayLoad
							 | 
						||
| 
								 | 
							
									    rdfe_update/4,		% Sub, Pred, Obj, +Action
							 | 
						||
| 
								 | 
							
									    rdfe_update/5,		% Sub, Pred, Obj, +PayLoad, +Action
							 | 
						||
| 
								 | 
							
									    rdfe_load/1,		% +File
							 | 
						||
| 
								 | 
							
									    rdfe_load/2,		% +File, +Options
							 | 
						||
| 
								 | 
							
									    rdfe_delete/1,		% +Resource
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_register_ns/2,		% +Id, +URI
							 | 
						||
| 
								 | 
							
									    rdfe_unregister_ns/2,	% +Id, +URI
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_reset/0,		% clear everything
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_transaction/1,		% :Goal
							 | 
						||
| 
								 | 
							
									    rdfe_transaction/2,		% :Goal, +Name
							 | 
						||
| 
								 | 
							
									    rdfe_transaction_member/2,	% +Transactions, -Action
							 | 
						||
| 
								 | 
							
									    rdfe_transaction_name/2,	% +Transactions, -Name
							 | 
						||
| 
								 | 
							
									    rdfe_set_transaction_name/1,% +Name
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_set_watermark/1,	% +Name
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_undo/0,		%
							 | 
						||
| 
								 | 
							
									    rdfe_redo/0,
							 | 
						||
| 
								 | 
							
									    rdfe_can_undo/1,		% -TID
							 | 
						||
| 
								 | 
							
									    rdfe_can_redo/1,		% -TID
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_set_file_property/2,	% +File, +Property
							 | 
						||
| 
								 | 
							
									    rdfe_get_file_property/2,	% ?File, ?Property
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_is_modified/1,		% ?File
							 | 
						||
| 
								 | 
							
									    rdfe_clear_modified/1,	% +File
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_open_journal/2,	% +File, +Mode
							 | 
						||
| 
								 | 
							
									    rdfe_close_journal/0,
							 | 
						||
| 
								 | 
							
									    rdfe_replay_journal/1,	% +File
							 | 
						||
| 
								 | 
							
									    rdfe_current_journal/1,	% -Path
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									    rdfe_snapshot_file/1	% -File
							 | 
						||
| 
								 | 
							
									  ]).
							 | 
						||
| 
								 | 
							
								:- use_module(rdf_db).
							 | 
						||
| 
								 | 
							
								:- use_module(library(broadcast)).
							 | 
						||
| 
								 | 
							
								:- use_module(library(lists)).
							 | 
						||
| 
								 | 
							
								:- use_module(library(debug)).
							 | 
						||
| 
								 | 
							
								:- use_module(library(url)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- meta_predicate
							 | 
						||
| 
								 | 
							
									rdfe_transaction(:),
							 | 
						||
| 
								 | 
							
									rdfe_transaction(:, +).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- dynamic
							 | 
						||
| 
								 | 
							
									undo_log/5,			% TID, Action, Subj, Pred, Obj
							 | 
						||
| 
								 | 
							
									current_transaction/1,		% TID
							 | 
						||
| 
								 | 
							
									transaction_name/2,		% TID, Name
							 | 
						||
| 
								 | 
							
									undo_marker/2,			% Mode, TID
							 | 
						||
| 
								 | 
							
									journal/3,			% Path, Mode, Stream
							 | 
						||
| 
								 | 
							
									unmodified_md5/2,		% Path, MD5
							 | 
						||
| 
								 | 
							
									snapshot_file/1.		% File
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** <module> RDF edit layer
							 | 
						||
| 
								 | 
							
								This library provides a number of functions on top of the rdf_db module:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    * Broadcast modifications
							 | 
						||
| 
								 | 
							
								    * Provide undo/redo
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@tbd	This library must be rewritten using rdf_monitor/3.  This allows
							 | 
						||
| 
								 | 
							
									using edit layer without having to choose between rdf_ and rdfe_
							 | 
						||
| 
								 | 
							
									predicates.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								@see	rdf_persistency.pl provides reliable persistency, but without
							 | 
						||
| 
								 | 
							
									changes boardcasting and undo/redo.
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- rdf_meta
							 | 
						||
| 
								 | 
							
									rdfe_assert(r,r,o),
							 | 
						||
| 
								 | 
							
									rdfe_assert(r,r,o,+),
							 | 
						||
| 
								 | 
							
									rdfe_retractall(r,r,o),
							 | 
						||
| 
								 | 
							
									rdfe_update(r,r,o,t),
							 | 
						||
| 
								 | 
							
									rdfe_delete(r),
							 | 
						||
| 
								 | 
							
									rdfe_transaction(:),
							 | 
						||
| 
								 | 
							
									rdfe_transaction(:, +).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *     BASIC EDIT OPERATIONS	*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_assert(Subject, Predicate, Object) :-
							 | 
						||
| 
								 | 
							
									rdfe_assert(Subject, Predicate, Object, user).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_assert(Subject, Predicate, Object, PayLoad) :-
							 | 
						||
| 
								 | 
							
									rdf_assert(Subject, Predicate, Object, PayLoad),
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									assert_action(TID, assert(PayLoad), Subject, Predicate, Object),
							 | 
						||
| 
								 | 
							
									journal(assert(TID, Subject, Predicate, Object, PayLoad)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_retractall(Subject, Predicate, Object) :-
							 | 
						||
| 
								 | 
							
									rdfe_retractall(Subject, Predicate, Object, _).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_retractall(Subject, Predicate, Object, PayLoad) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									(   rdf(Subject, Predicate, Object, PayLoad),
							 | 
						||
| 
								 | 
							
									    assert_action(TID, retract(PayLoad), Subject, Predicate, Object),
							 | 
						||
| 
								 | 
							
									    journal(retract(TID, Subject, Predicate, Object, PayLoad)),
							 | 
						||
| 
								 | 
							
									    fail
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									rdf_retractall(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_update(+Subject, +Predicate, +Object, +Action)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Update an existing triple.  Possible actions are:
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%%		subject(+Subject)
							 | 
						||
| 
								 | 
							
								%%		predicate(+Predicate)
							 | 
						||
| 
								 | 
							
								%%		object(+Object)
							 | 
						||
| 
								 | 
							
								%%		source(+Source)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_update(Subject, Predicate, Object, Action) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									rdf_update(Subject, Predicate, Object, Action),
							 | 
						||
| 
								 | 
							
									(   Action = object(New)
							 | 
						||
| 
								 | 
							
									->  assert_action(TID, object(Object), Subject, Predicate, New)
							 | 
						||
| 
								 | 
							
									;   Action = predicate(New)
							 | 
						||
| 
								 | 
							
									->  assert_action(TID, predicate(Predicate), Subject, New, Object)
							 | 
						||
| 
								 | 
							
									;   Action = subject(New)
							 | 
						||
| 
								 | 
							
									->  assert_action(TID, subject(Subject), New, Predicate, Object)
							 | 
						||
| 
								 | 
							
									;   Action = source(New)
							 | 
						||
| 
								 | 
							
									->  forall(rdf(Subject, Predicate, Object, PayLoad),
							 | 
						||
| 
								 | 
							
										   assert_action(TID, source(PayLoad, New),
							 | 
						||
| 
								 | 
							
												 Subject, Predicate, Object))
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									journal(update(TID, Subject, Predicate, Object, Action)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_update(Subject, Predicate, Object, PayLoad, Action) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									rdf_update(Subject, Predicate, Object, PayLoad, Action),
							 | 
						||
| 
								 | 
							
									(   Action = source(New)
							 | 
						||
| 
								 | 
							
									->  assert_action(TID, source(PayLoad, New),
							 | 
						||
| 
								 | 
							
											  Subject, Predicate, Object)
							 | 
						||
| 
								 | 
							
									;   throw(tbd)			% source is used internally
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									journal(update(TID, Subject, Predicate, Object, PayLoad, Action)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_delete(+Subject)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Delete a subject and all we know about it. This is a bit tricky.
							 | 
						||
| 
								 | 
							
								%	If we are involved in transitive relations, should we re-joint
							 | 
						||
| 
								 | 
							
								%	these in this module?
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_delete(Subject) :-
							 | 
						||
| 
								 | 
							
									rdfe_transaction(delete(Subject)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								delete(Subject) :-
							 | 
						||
| 
								 | 
							
									rdfe_retractall(Subject, _, _),
							 | 
						||
| 
								 | 
							
									rdfe_retractall(_, Subject, _),
							 | 
						||
| 
								 | 
							
									rdfe_retractall(_, _, Subject).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	   FILE HANDLING	*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_load(+File) is det.
							 | 
						||
| 
								 | 
							
								%%	rdfe_load(+File, +Options) is det.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Load an RDF file and record this action including version information
							 | 
						||
| 
								 | 
							
								%	to facilitate reliable reload.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_load(File) :-
							 | 
						||
| 
								 | 
							
									rdfe_load(File, []).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_load(File, Options) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									absolute_file_name(File,
							 | 
						||
| 
								 | 
							
											   [ access(read),
							 | 
						||
| 
								 | 
							
											     extensions([rdf,rdfs,owl,''])
							 | 
						||
| 
								 | 
							
											   ], Path),
							 | 
						||
| 
								 | 
							
									rdf_load(Path,
							 | 
						||
| 
								 | 
							
										 [ graph(Graph),
							 | 
						||
| 
								 | 
							
										   modified(Modified)
							 | 
						||
| 
								 | 
							
										 | Options
							 | 
						||
| 
								 | 
							
										 ]),
							 | 
						||
| 
								 | 
							
									(   Modified == not_modified
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   absolute_file_name('.', PWD),
							 | 
						||
| 
								 | 
							
									    size_file(Path, Size),
							 | 
						||
| 
								 | 
							
									    (	Modified = last_modified(Stamp)
							 | 
						||
| 
								 | 
							
									    ->	true
							 | 
						||
| 
								 | 
							
									    ;	time_file(Path, Stamp)
							 | 
						||
| 
								 | 
							
									    ),
							 | 
						||
| 
								 | 
							
									    SecTime is round(Stamp),
							 | 
						||
| 
								 | 
							
									    rdf_statistics(triples_by_file(Graph, Triples)),
							 | 
						||
| 
								 | 
							
									    rdf_md5(Graph, MD5),
							 | 
						||
| 
								 | 
							
									    assert_action(TID, load_file(Path), -, -, -),
							 | 
						||
| 
								 | 
							
									    journal(rdf_load(TID,
							 | 
						||
| 
								 | 
							
											     Path,
							 | 
						||
| 
								 | 
							
											     [ pwd(PWD),
							 | 
						||
| 
								 | 
							
											       size(Size),
							 | 
						||
| 
								 | 
							
											       modified(SecTime),
							 | 
						||
| 
								 | 
							
											       triples(Triples),
							 | 
						||
| 
								 | 
							
											       md5(MD5),
							 | 
						||
| 
								 | 
							
											       from(File)
							 | 
						||
| 
								 | 
							
											     ])),
							 | 
						||
| 
								 | 
							
									    ensure_snapshot(Path)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_unload(Path) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									rdf_unload(Path),
							 | 
						||
| 
								 | 
							
									assert_action(TID, unload_file(Path), -, -, -),
							 | 
						||
| 
								 | 
							
									journal(rdf_unload(TID, Path)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	ensure_snapshot(+Path)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Ensure we have a snapshot of Path if we are making a journal, so
							 | 
						||
| 
								 | 
							
								%	we can always reload the snapshot to ensure exactly the same
							 | 
						||
| 
								 | 
							
								%	state.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ensure_snapshot(Path) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_journal(_),
							 | 
						||
| 
								 | 
							
									rdf_md5(Path, MD5),
							 | 
						||
| 
								 | 
							
									(   snapshot_file(Path, MD5,
							 | 
						||
| 
								 | 
							
											  [ access(read),
							 | 
						||
| 
								 | 
							
											    file_errors(fail)
							 | 
						||
| 
								 | 
							
											  ],
							 | 
						||
| 
								 | 
							
											  File)
							 | 
						||
| 
								 | 
							
									->  debug(snapshot, 'Existing snapshot for ~w on ~w', [Path, File])
							 | 
						||
| 
								 | 
							
									;   snapshot_file(Path, MD5,
							 | 
						||
| 
								 | 
							
											  [ access(write)
							 | 
						||
| 
								 | 
							
											  ],
							 | 
						||
| 
								 | 
							
											  File),
							 | 
						||
| 
								 | 
							
									    debug(snapshot, 'Saving snapshot for ~w to ~w', [Path, File]),
							 | 
						||
| 
								 | 
							
									    rdf_save_db(File, Path)
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									assert(snapshot_file(File)).
							 | 
						||
| 
								 | 
							
								ensure_snapshot(_).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	load_snapshot(+Source, +Path)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Load triples from the given snapshot   file. One of the troubles
							 | 
						||
| 
								 | 
							
								%	is the time-stamp to avoid rdf_make/0   from reloading the file.
							 | 
						||
| 
								 | 
							
								%	for the time being we use 1e12, which   is  a lot further in the
							 | 
						||
| 
								 | 
							
								%	future than this system is going to live.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								load_snapshot(Source, Path) :-
							 | 
						||
| 
								 | 
							
									statistics(cputime, T0),
							 | 
						||
| 
								 | 
							
									rdf_load_db(Path),
							 | 
						||
| 
								 | 
							
									statistics(cputime, T1),
							 | 
						||
| 
								 | 
							
									Time is T1 - T0,
							 | 
						||
| 
								 | 
							
									rdf_statistics(triples_by_file(Source, Triples)),
							 | 
						||
| 
								 | 
							
									rdf_md5(Source, MD5),
							 | 
						||
| 
								 | 
							
													% 1e10: modified far in the future
							 | 
						||
| 
								 | 
							
									assert(rdf_db:rdf_source(Source, 1e12, Triples, MD5)),
							 | 
						||
| 
								 | 
							
									print_message(informational,
							 | 
						||
| 
								 | 
							
										      rdf(loaded(Source, Triples, snapshot(Time)))),
							 | 
						||
| 
								 | 
							
									assert(snapshot_file(Path)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	snapshot_file(+Path, +MD5, +Access, -File)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Find existing snapsnot file or location to save a new one.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								snapshot_file(Path, MD5, Options, SnapShot) :-
							 | 
						||
| 
								 | 
							
									file_base_name(Path, Base),
							 | 
						||
| 
								 | 
							
									atomic_list_concat([Base, @, MD5], File),
							 | 
						||
| 
								 | 
							
									absolute_file_name(snapshot(File),
							 | 
						||
| 
								 | 
							
											   [ extensions([trp])
							 | 
						||
| 
								 | 
							
											   | Options
							 | 
						||
| 
								 | 
							
											   ],
							 | 
						||
| 
								 | 
							
											   SnapShot).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_snapshot_file(-File)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Enumerate the MD5 snapshot files required to restore the current
							 | 
						||
| 
								 | 
							
								%	journal file. Using this  call  we   can  write  a  routine that
							 | 
						||
| 
								 | 
							
								%	packages the journal file with all required snapshots to restore
							 | 
						||
| 
								 | 
							
								%	the journal on another computer.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_snapshot_file(File) :-
							 | 
						||
| 
								 | 
							
									snapshot_file(File).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	NAMESPACE HANDLING	*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- dynamic
							 | 
						||
| 
								 | 
							
									system_ns/2.
							 | 
						||
| 
								 | 
							
								:- volatile
							 | 
						||
| 
								 | 
							
									system_ns/2.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_register_ns(Id, URI)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Encapsulation of rdf_register_ns(Id, URI)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_register_ns(Id, URI) :-
							 | 
						||
| 
								 | 
							
									rdf_db:ns(Id, URI), !.
							 | 
						||
| 
								 | 
							
								rdfe_register_ns(Id, URI) :-
							 | 
						||
| 
								 | 
							
									save_system_ns,
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									rdf_register_ns(Id, URI),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_ns(register(Id, URI))),
							 | 
						||
| 
								 | 
							
									assert_action(TID, ns(register(Id, URI)), -, -, -),
							 | 
						||
| 
								 | 
							
									journal(ns(TID, register(Id, URI))).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_unregister_ns(Id, URI) :-
							 | 
						||
| 
								 | 
							
									save_system_ns,
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									retractall(rdf_db:ns(Id, URI)),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_ns(unregister(Id, URI))),
							 | 
						||
| 
								 | 
							
									assert_action(TID, ns(unregister(Id, URI)), -, -, -),
							 | 
						||
| 
								 | 
							
									journal(ns(TID, unregister(Id, URI))).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%	rdfe_register_ns/0
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Reset namespaces to the state they where before usage of the
							 | 
						||
| 
								 | 
							
								%	rdf_edit layer.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_reset_ns :-
							 | 
						||
| 
								 | 
							
									(   system_ns(_, _)
							 | 
						||
| 
								 | 
							
									->  retractall(rdf_db:ns(Id, URI)),
							 | 
						||
| 
								 | 
							
									    forall(system_ns(Id, URI), assert(rdb_db:ns(Id, URI)))
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								save_system_ns :-
							 | 
						||
| 
								 | 
							
									system_ns(_, _), !.		% already done
							 | 
						||
| 
								 | 
							
								save_system_ns :-
							 | 
						||
| 
								 | 
							
									forall(rdf_db:ns(Id, URI), assert(system_ns(Id, URI))).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	   TRANSACTIONS		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_transaction(:Goal)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Run Goal, recording all modifications   as a single transaction.
							 | 
						||
| 
								 | 
							
								%	If  Goal  raises  an  exception  or    fails,  all  changes  are
							 | 
						||
| 
								 | 
							
								%	rolled-back.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_transaction(Goal) :-
							 | 
						||
| 
								 | 
							
									rdfe_transaction(Goal, []).
							 | 
						||
| 
								 | 
							
								rdfe_transaction(Goal, Name) :-
							 | 
						||
| 
								 | 
							
									rdfe_begin_transaction(Name),
							 | 
						||
| 
								 | 
							
									(   catch(Goal, E, true)
							 | 
						||
| 
								 | 
							
									->  (   var(E)
							 | 
						||
| 
								 | 
							
									    ->	check_file_protection(Error),
							 | 
						||
| 
								 | 
							
										(   var(Error)
							 | 
						||
| 
								 | 
							
										->  rdfe_commit
							 | 
						||
| 
								 | 
							
										;   rdfe_rollback,
							 | 
						||
| 
								 | 
							
										    throw(Error)
							 | 
						||
| 
								 | 
							
										)
							 | 
						||
| 
								 | 
							
									    ;	rdfe_rollback,
							 | 
						||
| 
								 | 
							
										throw(E)
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;   rdfe_rollback,
							 | 
						||
| 
								 | 
							
									    fail
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_begin_transaction
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Start a transaction.  This is followed by either rdfe_end_transaction
							 | 
						||
| 
								 | 
							
								%	or rdfe_rollback.  Transactions may be nested.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_begin_transaction(Name) :-
							 | 
						||
| 
								 | 
							
									current_transaction(TID), !,	% nested transaction
							 | 
						||
| 
								 | 
							
									append(TID, [1], TID2),
							 | 
						||
| 
								 | 
							
									asserta(current_transaction(TID2)),
							 | 
						||
| 
								 | 
							
									assert(transaction_name(TID2, Name)).
							 | 
						||
| 
								 | 
							
								rdfe_begin_transaction(Name) :-		% toplevel transaction
							 | 
						||
| 
								 | 
							
									flag(rdf_edit_tid, TID, TID+1),
							 | 
						||
| 
								 | 
							
									asserta(current_transaction([TID])),
							 | 
						||
| 
								 | 
							
									assert(transaction_name(TID, Name)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_current_transaction(TID) :-
							 | 
						||
| 
								 | 
							
									current_transaction(TID), !.
							 | 
						||
| 
								 | 
							
								rdfe_current_transaction(_) :-
							 | 
						||
| 
								 | 
							
									throw(error(existence_error(rdf_transaction, _), _)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_commit :-
							 | 
						||
| 
								 | 
							
									retract(current_transaction(TID)), !,
							 | 
						||
| 
								 | 
							
									retractall(undo_marker(_, _)),
							 | 
						||
| 
								 | 
							
									(   rdfe_transaction_member(TID, _)
							 | 
						||
| 
								 | 
							
									->  get_time(Time),		% transaction is not empty
							 | 
						||
| 
								 | 
							
									    journal(commit(TID, Time)),
							 | 
						||
| 
								 | 
							
									    (   TID = [Id]
							 | 
						||
| 
								 | 
							
									    ->  broadcast(rdf_transaction(Id))
							 | 
						||
| 
								 | 
							
									    ;   true
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_rollback :-
							 | 
						||
| 
								 | 
							
									retract(current_transaction(TID)), !,
							 | 
						||
| 
								 | 
							
									journal(rollback(TID)),
							 | 
						||
| 
								 | 
							
									rollback(TID).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rollback(+TID)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	This is the same as undo/1, but it must not record the undone
							 | 
						||
| 
								 | 
							
								%	actions as rollbacks cannot be `redone'.  Somehow there should
							 | 
						||
| 
								 | 
							
								%	be a cleaner way to distinguish between transactional operations
							 | 
						||
| 
								 | 
							
								%	and plain operations.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rollback(TID) :-
							 | 
						||
| 
								 | 
							
									append(TID, _, Id),
							 | 
						||
| 
								 | 
							
									(   retract(undo_log(Id, Action, Subject, Predicate, Object)),
							 | 
						||
| 
								 | 
							
									    (	rollback(Action, Subject, Predicate, Object)
							 | 
						||
| 
								 | 
							
									    ->	fail
							 | 
						||
| 
								 | 
							
									    ;	print_message(error,
							 | 
						||
| 
								 | 
							
											      rdf_undo_failed(undo(Action, Subject,
							 | 
						||
| 
								 | 
							
														   Predicate, Object))),
							 | 
						||
| 
								 | 
							
										fail
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rollback(assert(PayLoad), Subject, Predicate, Object) :- !,
							 | 
						||
| 
								 | 
							
									rdf_retractall(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								rollback(retract(PayLoad), Subject, Predicate, Object) :- !,
							 | 
						||
| 
								 | 
							
									rdf_assert(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								rollback(Action, Subject, Predicate, Object) :-
							 | 
						||
| 
								 | 
							
									action(Action), !,
							 | 
						||
| 
								 | 
							
									rdf_update(Subject, Predicate, Object, Action).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								assert_action(TID, Action, Subject, Predicate, Object) :-
							 | 
						||
| 
								 | 
							
									asserta(undo_log(TID, Action, Subject, Predicate, Object)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	undo(+TID)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Undo a transaction as well as possible transactions nested into
							 | 
						||
| 
								 | 
							
								%	it.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								undo(TID) :-
							 | 
						||
| 
								 | 
							
									append(TID, _, Id),
							 | 
						||
| 
								 | 
							
									(   retract(undo_log(Id, Action, Subject, Predicate, Object)),
							 | 
						||
| 
								 | 
							
									    (	undo(Action, Subject, Predicate, Object)
							 | 
						||
| 
								 | 
							
									    ->	fail
							 | 
						||
| 
								 | 
							
									    ;	print_message(warning,
							 | 
						||
| 
								 | 
							
											      rdf_undo_failed(undo(Action, Subject,
							 | 
						||
| 
								 | 
							
														   Predicate, Object))),
							 | 
						||
| 
								 | 
							
										fail
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								undo(assert(PayLoad), Subject, Predicate, Object) :- !,
							 | 
						||
| 
								 | 
							
									rdfe_retractall(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								undo(retract(PayLoad), Subject, Predicate, Object) :- !,
							 | 
						||
| 
								 | 
							
									rdfe_assert(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								undo(source(Old, New), Subject, Predicate, Object) :- !,
							 | 
						||
| 
								 | 
							
									rdfe_update(Subject, Predicate, Object, Old, source(New)).
							 | 
						||
| 
								 | 
							
								undo(ns(Action), -, -, -) :- !,
							 | 
						||
| 
								 | 
							
									(   Action = register(Id, URI)
							 | 
						||
| 
								 | 
							
									->  rdfe_unregister_ns(Id, URI)
							 | 
						||
| 
								 | 
							
									;   Action = unregister(Id, URI)
							 | 
						||
| 
								 | 
							
									->  rdfe_register_ns(Id, URI)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								undo(load_file(Path), -, -, -) :- !,
							 | 
						||
| 
								 | 
							
									rdfe_unload(Path).
							 | 
						||
| 
								 | 
							
								undo(unload_file(Path), -, -, -) :- !,
							 | 
						||
| 
								 | 
							
									rdfe_load(Path).
							 | 
						||
| 
								 | 
							
								undo(Action, Subject, Predicate, Object) :-
							 | 
						||
| 
								 | 
							
									action(Action), !,
							 | 
						||
| 
								 | 
							
									rdfe_update(Subject, Predicate, Object, Action).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								action(subject(_)).
							 | 
						||
| 
								 | 
							
								action(predicate(_)).
							 | 
						||
| 
								 | 
							
								action(object(_)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_undo
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Undo a (toplevel) transaction. More calls do further undo. The
							 | 
						||
| 
								 | 
							
								%	`Undone' actions are re-added to the undo log, so the user can
							 | 
						||
| 
								 | 
							
								%	redo them.  Fails if there are no more undo/redo transactions.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_undo :-
							 | 
						||
| 
								 | 
							
									undo_marker(undo, TID), !,
							 | 
						||
| 
								 | 
							
									(   undo_previous(TID, UnDone)
							 | 
						||
| 
								 | 
							
									->  retractall(undo_marker(_, _)),
							 | 
						||
| 
								 | 
							
									    assert(undo_marker(undo, UnDone)),
							 | 
						||
| 
								 | 
							
									    broadcast(rdf_undo(undo, UnDone))
							 | 
						||
| 
								 | 
							
									;   fail			% start of undo log
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								rdfe_undo :-
							 | 
						||
| 
								 | 
							
									retract(undo_marker(redo, _)), !,
							 | 
						||
| 
								 | 
							
									last_transaction(TID),
							 | 
						||
| 
								 | 
							
									undo_previous(TID, UnDone),
							 | 
						||
| 
								 | 
							
									assert(undo_marker(undo, UnDone)),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_undo(undo, UnDone)).
							 | 
						||
| 
								 | 
							
								rdfe_undo :-
							 | 
						||
| 
								 | 
							
									last_transaction(TID),
							 | 
						||
| 
								 | 
							
									undo_previous(TID, UnDone),
							 | 
						||
| 
								 | 
							
									assert(undo_marker(undo, UnDone)),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_undo(undo, UnDone)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								find_previous_undo(-1, _) :- !,
							 | 
						||
| 
								 | 
							
									fail.
							 | 
						||
| 
								 | 
							
								find_previous_undo(TID, TID) :-
							 | 
						||
| 
								 | 
							
									undo_log([TID|_], _, _, _, _), !.
							 | 
						||
| 
								 | 
							
								find_previous_undo(TID0, TID) :-
							 | 
						||
| 
								 | 
							
									TID1 is TID0 - 1,
							 | 
						||
| 
								 | 
							
									find_previous_undo(TID1, TID).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								undo_previous(TID, Undone) :-
							 | 
						||
| 
								 | 
							
									find_previous_undo(TID, Undone),
							 | 
						||
| 
								 | 
							
									rdfe_transaction(undo([Undone])).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								last_transaction(TID) :-
							 | 
						||
| 
								 | 
							
									undo_log([TID|_], _, _, _, _), !.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_redo
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Start a redo-session
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_redo :-
							 | 
						||
| 
								 | 
							
									(   retract(undo_marker(undo, _))
							 | 
						||
| 
								 | 
							
									->  last_transaction(TID),
							 | 
						||
| 
								 | 
							
									    undo_previous(TID, UnDone),
							 | 
						||
| 
								 | 
							
									    assert(undo_marker(redo, UnDone))
							 | 
						||
| 
								 | 
							
									;   retract(undo_marker(redo, TID))
							 | 
						||
| 
								 | 
							
									->  undo_previous(TID, UnDone),
							 | 
						||
| 
								 | 
							
									    assert(undo_marker(redo, UnDone))
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_undo(redo, UnDone)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_can_redo(-TID) is semidet.
							 | 
						||
| 
								 | 
							
								%%	rdfe_can_undo(-TID) is semidet.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Check if we can undo and if so return the id of the transaction
							 | 
						||
| 
								 | 
							
								%	that will be un/re-done.  A subsequent call to rdfe_transaction_name
							 | 
						||
| 
								 | 
							
								%	can be used to give a hint in the UI.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_can_redo(Redo) :-
							 | 
						||
| 
								 | 
							
									undo_marker(undo, _), !,
							 | 
						||
| 
								 | 
							
									last_transaction(TID),
							 | 
						||
| 
								 | 
							
									find_previous_undo(TID, Redo).
							 | 
						||
| 
								 | 
							
								rdfe_can_redo(Redo) :-
							 | 
						||
| 
								 | 
							
									undo_marker(redo, TID),
							 | 
						||
| 
								 | 
							
									find_previous_undo(TID, Redo).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_can_undo(Undo) :-			% continue undo
							 | 
						||
| 
								 | 
							
									undo_marker(undo, TID), !,
							 | 
						||
| 
								 | 
							
									find_previous_undo(TID, Undo).
							 | 
						||
| 
								 | 
							
								rdfe_can_undo(Undo) :-			% start undo
							 | 
						||
| 
								 | 
							
									last_transaction(TID),
							 | 
						||
| 
								 | 
							
									find_previous_undo(TID, Undo).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_transaction_name(+TID, -Name)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Return name if the transaction is named.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_transaction_name(TID, Name) :-
							 | 
						||
| 
								 | 
							
									transaction_name(TID, Name),
							 | 
						||
| 
								 | 
							
									Name \== [].
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_set_transaction_name(+Name)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Set name of the current transaction
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_set_transaction_name(Name) :-
							 | 
						||
| 
								 | 
							
									current_transaction(TID), !,
							 | 
						||
| 
								 | 
							
									assert(transaction_name(TID, Name)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_transaction_member(+TID, -Action)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Query actions inside a transaction to allow for quick update
							 | 
						||
| 
								 | 
							
								%	of visualisers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_transaction_member(TID, Member) :-
							 | 
						||
| 
								 | 
							
									(   integer(TID)
							 | 
						||
| 
								 | 
							
									->  Id = [TID|_]
							 | 
						||
| 
								 | 
							
									;   append(TID, _, Id)
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									undo_log(Id, Action, Subject, Predicate, Object),
							 | 
						||
| 
								 | 
							
									user_transaction_member(Action, Subject, Predicate, Object, Member).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								user_transaction_member(assert(_), Subject, Predicate, Object,
							 | 
						||
| 
								 | 
							
											assert(Subject, Predicate, Object)) :- !.
							 | 
						||
| 
								 | 
							
								user_transaction_member(retract(_), Subject, Predicate, Object,
							 | 
						||
| 
								 | 
							
											retract(Subject, Predicate, Object)) :- !.
							 | 
						||
| 
								 | 
							
								user_transaction_member(load_file(Path), -, -, -,
							 | 
						||
| 
								 | 
							
											file(load(Path))) :- !.
							 | 
						||
| 
								 | 
							
								user_transaction_member(unload_file(Path), -, -, -,
							 | 
						||
| 
								 | 
							
											file(unload(Path))) :- !.
							 | 
						||
| 
								 | 
							
								user_transaction_member(Update, Subject, Predicate, Object,
							 | 
						||
| 
								 | 
							
											update(Subject, Predicate, Object, Update)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	     PROTECTION		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- dynamic
							 | 
						||
| 
								 | 
							
									rdf_source_permission/2,	% file, ro/rw
							 | 
						||
| 
								 | 
							
									rdf_current_default_file/2.	% file, all/fallback
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_set_file_property(+File, +Options)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Set properties on the file.  Options is one of
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%		* access(ro/rw)
							 | 
						||
| 
								 | 
							
								%		* default(all/fallback)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_set_file_property(File, access(Access)) :- !,
							 | 
						||
| 
								 | 
							
									to_url(File, URL),
							 | 
						||
| 
								 | 
							
									retractall(rdf_source_permission(URL, _)),
							 | 
						||
| 
								 | 
							
									assert(rdf_source_permission(URL, Access)),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_file_property(URL, access(Access))).
							 | 
						||
| 
								 | 
							
								rdfe_set_file_property(File, default(Type)) :-
							 | 
						||
| 
								 | 
							
									to_url(File, URL),
							 | 
						||
| 
								 | 
							
									rdfe_set_file_property(URL, access(rw)), % must be writeable
							 | 
						||
| 
								 | 
							
									retractall(rdf_current_default_file(_,_)),
							 | 
						||
| 
								 | 
							
									assert(rdf_current_default_file(URL, Type)),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_file_property(URL, default(Type))).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_get_file_property(+FileOrURL, ?Option).
							 | 
						||
| 
								 | 
							
								%%	rdfe_get_file_property(-URL, ?Option).
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Fetch file properties set with rdfe_set_file_property/2.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_get_file_property(FileOrURL, access(Access)) :-
							 | 
						||
| 
								 | 
							
									(   ground(FileOrURL)
							 | 
						||
| 
								 | 
							
									->  to_url(FileOrURL, URL)
							 | 
						||
| 
								 | 
							
									;   rdf_source(_DB, URL),
							 | 
						||
| 
								 | 
							
									    FileOrURL = URL
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									(   rdf_source_permission(URL, Access0)
							 | 
						||
| 
								 | 
							
									->  Access0 = Access
							 | 
						||
| 
								 | 
							
									;   access_file(URL, write)
							 | 
						||
| 
								 | 
							
									->  assert(rdf_source_permission(URL, rw)),
							 | 
						||
| 
								 | 
							
									    Access = rw
							 | 
						||
| 
								 | 
							
									;   assert(rdf_source_permission(URL, ro)),
							 | 
						||
| 
								 | 
							
									    Access = ro
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								rdfe_get_file_property(FileOrURL, default(Default)) :-
							 | 
						||
| 
								 | 
							
									ground(FileOrURL),
							 | 
						||
| 
								 | 
							
									to_url(FileOrURL, URL),
							 | 
						||
| 
								 | 
							
									(   rdf_current_default_file(URL, Default)
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   FileOrURL = user,
							 | 
						||
| 
								 | 
							
									    Default = fallback
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								rdfe_get_file_property(URL, default(Default)) :-
							 | 
						||
| 
								 | 
							
									(   rdf_current_default_file(URL, Default)
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   URL = user,
							 | 
						||
| 
								 | 
							
									    Default = fallback
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	check_file_protection(-Error)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Check modification of all protected files
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								check_file_protection(Error) :-
							 | 
						||
| 
								 | 
							
									(   rdfe_get_file_property(File, access(ro)),
							 | 
						||
| 
								 | 
							
									    rdfe_is_modified(File)
							 | 
						||
| 
								 | 
							
									->  Error = error(permission_error(modify, source, File), triple20)
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	to_url(+Spec, -URL) is det.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Convert a specification into a URL.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								to_url(URL, URL) :-
							 | 
						||
| 
								 | 
							
									atom(URL),
							 | 
						||
| 
								 | 
							
									sub_atom(URL, B, _, _, '://'),
							 | 
						||
| 
								 | 
							
									sub_atom(URL, 0, B, _, Protocol),
							 | 
						||
| 
								 | 
							
									url_protocol(Protocol), !.
							 | 
						||
| 
								 | 
							
								to_url(File, URL) :-
							 | 
						||
| 
								 | 
							
									file_name_to_url(File, URL).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								url_protocol(file).
							 | 
						||
| 
								 | 
							
								url_protocol(http).
							 | 
						||
| 
								 | 
							
								url_protocol(https).
							 | 
						||
| 
								 | 
							
								url_protocol(ftp).
							 | 
						||
| 
								 | 
							
								url_protocol(ftps).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	     MODIFIED		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_is_modified(?Source)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	True if facts have been added, deleted or updated that have
							 | 
						||
| 
								 | 
							
								%	Source as `payload'.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_is_modified(Source) :-
							 | 
						||
| 
								 | 
							
									rdf_source(DB, Source),
							 | 
						||
| 
								 | 
							
									rdf_md5(DB, MD5),
							 | 
						||
| 
								 | 
							
									(   unmodified_md5(Source, UnmodifiedMD5)
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   rdf_db:rdf_source(DB, Source, _Time, _Triples, UnmodifiedMD5)
							 | 
						||
| 
								 | 
							
									),
							 | 
						||
| 
								 | 
							
									UnmodifiedMD5 \== MD5.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_clear_modified :-
							 | 
						||
| 
								 | 
							
									forall(rdf_graph(File),
							 | 
						||
| 
								 | 
							
									       rdfe_clear_modified(File)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_clear_modified(+DB) is det.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Consider the current state of DB as _unmodified_.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_clear_modified(DB) :-
							 | 
						||
| 
								 | 
							
									atom(DB),
							 | 
						||
| 
								 | 
							
									retractall(unmodified_md5(DB, _)),
							 | 
						||
| 
								 | 
							
									rdf_md5(DB, MD5),
							 | 
						||
| 
								 | 
							
									(   rdf_db:rdf_source(DB, _File, _Time, _Triples, UnmodifiedMD5),
							 | 
						||
| 
								 | 
							
									    MD5 == UnmodifiedMD5
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   assert(unmodified_md5(DB, MD5))
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	     WATERMARKS		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_set_watermark(Name)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Create a watermark for undo and replay journal upto this point.
							 | 
						||
| 
								 | 
							
								%	The rest of the logic needs to be written later.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_set_watermark(Name) :-
							 | 
						||
| 
								 | 
							
									rdfe_current_transaction(TID),
							 | 
						||
| 
								 | 
							
									assert_action(TID, watermark(Name), -, -, -),
							 | 
						||
| 
								 | 
							
									journal(watermark(TID, Name)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	       RESET		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_reset
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Clear database, undo, namespaces and journalling info.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_reset :-
							 | 
						||
| 
								 | 
							
									rdfe_reset_journal,
							 | 
						||
| 
								 | 
							
									rdfe_reset_ns,
							 | 
						||
| 
								 | 
							
									rdfe_reset_undo,
							 | 
						||
| 
								 | 
							
									rdf_reset_db,
							 | 
						||
| 
								 | 
							
									broadcast(rdf_reset).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_reset_journal
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	If a journal is open, close it using rdfe_close_journal/0
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_reset_journal :-
							 | 
						||
| 
								 | 
							
									(   rdfe_current_journal(_)
							 | 
						||
| 
								 | 
							
									->  rdfe_close_journal
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_reset_undo :-
							 | 
						||
| 
								 | 
							
									retractall(undo_log(_,_,_,_,_)),
							 | 
						||
| 
								 | 
							
									retractall(current_transaction(_)),
							 | 
						||
| 
								 | 
							
									retractall(transaction_name(_,_)),
							 | 
						||
| 
								 | 
							
									retractall(undo_marker(_,_)),
							 | 
						||
| 
								 | 
							
									retractall(unmodified_md5(_, _)),
							 | 
						||
| 
								 | 
							
									retractall(snapshot_file(_)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%	close possible open journal at exit.  Using a Prolog hook
							 | 
						||
| 
								 | 
							
								%	guarantees closure, even for most crashes.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- at_halt(rdfe_reset_journal).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	    JOURNALLING		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								journal_version(1).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_open_journal(+File, +Mode) is det.
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Open a journal writing to File in Mode.  Mode is one of
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%		* read
							 | 
						||
| 
								 | 
							
								%		Open and replay the journal
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%		* write
							 | 
						||
| 
								 | 
							
								%		Delete current journal and create a fresh one
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%		* append
							 | 
						||
| 
								 | 
							
								%		Read and replay the existing journal and append new
							 | 
						||
| 
								 | 
							
								%		modifications to the File.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_open_journal(_, _) :-		% already open
							 | 
						||
| 
								 | 
							
									journal(_, _, _), !.
							 | 
						||
| 
								 | 
							
								rdfe_open_journal(File, read) :- !,
							 | 
						||
| 
								 | 
							
									absolute_file_name(File,
							 | 
						||
| 
								 | 
							
											   [ extensions([rdfj, '']),
							 | 
						||
| 
								 | 
							
											     access(read)
							 | 
						||
| 
								 | 
							
											   ],
							 | 
						||
| 
								 | 
							
											   Path),
							 | 
						||
| 
								 | 
							
									rdfe_replay_journal(Path),
							 | 
						||
| 
								 | 
							
									rdfe_clear_modified.
							 | 
						||
| 
								 | 
							
								rdfe_open_journal(File, write) :- !,
							 | 
						||
| 
								 | 
							
									absolute_file_name(File,
							 | 
						||
| 
								 | 
							
											   [ extensions([rdfj, '']),
							 | 
						||
| 
								 | 
							
											     access(write)
							 | 
						||
| 
								 | 
							
											   ],
							 | 
						||
| 
								 | 
							
											   Path),
							 | 
						||
| 
								 | 
							
									open(Path, write, Stream, [close_on_abort(false)]),
							 | 
						||
| 
								 | 
							
									assert(journal(Path, write, Stream)),
							 | 
						||
| 
								 | 
							
									get_time(T),
							 | 
						||
| 
								 | 
							
									journal_open(start, T).
							 | 
						||
| 
								 | 
							
								rdfe_open_journal(File, append) :-
							 | 
						||
| 
								 | 
							
									working_directory(CWD, CWD),
							 | 
						||
| 
								 | 
							
									absolute_file_name(File,
							 | 
						||
| 
								 | 
							
											   [ extensions([rdfj, '']),
							 | 
						||
| 
								 | 
							
											     relative_to(CWD),
							 | 
						||
| 
								 | 
							
											     access(write)
							 | 
						||
| 
								 | 
							
											   ],
							 | 
						||
| 
								 | 
							
											   Path),
							 | 
						||
| 
								 | 
							
									(   exists_file(Path)
							 | 
						||
| 
								 | 
							
									->  rdfe_replay_journal(Path),
							 | 
						||
| 
								 | 
							
									    rdfe_clear_modified,
							 | 
						||
| 
								 | 
							
									    get_time(T),
							 | 
						||
| 
								 | 
							
									    assert(journal(Path, append(T), []))
							 | 
						||
| 
								 | 
							
									;   rdfe_open_journal(Path, write)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								journal_open(Type, Time) :-
							 | 
						||
| 
								 | 
							
									journal_comment(Type, Time),
							 | 
						||
| 
								 | 
							
									SecTime is round(Time),
							 | 
						||
| 
								 | 
							
									journal_version(Version),
							 | 
						||
| 
								 | 
							
									Start =.. [ Type, [ time(SecTime),
							 | 
						||
| 
								 | 
							
											    version(Version)
							 | 
						||
| 
								 | 
							
											  ]
							 | 
						||
| 
								 | 
							
										  ],
							 | 
						||
| 
								 | 
							
									journal(Start),
							 | 
						||
| 
								 | 
							
									broadcast(rdf_journal(Start)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								journal_comment(start, Time) :-
							 | 
						||
| 
								 | 
							
									journal(_, _, Stream),
							 | 
						||
| 
								 | 
							
									format_time(string(String), '%+', Time),
							 | 
						||
| 
								 | 
							
									format(Stream,
							 | 
						||
| 
								 | 
							
									       '/* Triple20 Journal File\n\n   \
							 | 
						||
| 
								 | 
							
									       Created: ~w\n   \
							 | 
						||
| 
								 | 
							
									       Triple20 by Jan Wielemaker <wielemak@science.uva.nl>\n\n   \
							 | 
						||
| 
								 | 
							
									       EDIT WITH CARE!\n\
							 | 
						||
| 
								 | 
							
									       */~n~n', [String]).
							 | 
						||
| 
								 | 
							
								journal_comment(resume, Time) :-
							 | 
						||
| 
								 | 
							
									journal(_, _, Stream),
							 | 
						||
| 
								 | 
							
									format_time(string(String), '%+', Time),
							 | 
						||
| 
								 | 
							
									format(Stream,
							 | 
						||
| 
								 | 
							
									       '\n\
							 | 
						||
| 
								 | 
							
									       /* Resumed: ~w\n\
							 | 
						||
| 
								 | 
							
									       */~n~n', [String]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_close_journal
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Close  the  journal.  Automatically  called    from  at  program
							 | 
						||
| 
								 | 
							
								%	termination from at_halt/1.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_close_journal :-
							 | 
						||
| 
								 | 
							
									get_time(T),
							 | 
						||
| 
								 | 
							
									SecTime is round(T),
							 | 
						||
| 
								 | 
							
									journal(end([ time(SecTime)
							 | 
						||
| 
								 | 
							
										    ])),
							 | 
						||
| 
								 | 
							
									retract(journal(_, Mode, Stream)),
							 | 
						||
| 
								 | 
							
									(   Mode = append(_)
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   close(Stream)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_current_journal(-Path)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Query the currently open journal
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_current_journal(Path) :-
							 | 
						||
| 
								 | 
							
									journal(Path, _Mode, _Stream).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								journal(Term) :-
							 | 
						||
| 
								 | 
							
									journal(Path, append(T), _), !,
							 | 
						||
| 
								 | 
							
									(   Term = end(_)
							 | 
						||
| 
								 | 
							
									->  true
							 | 
						||
| 
								 | 
							
									;   open(Path, append, Stream, [close_on_abort(false)]),
							 | 
						||
| 
								 | 
							
									    retractall(journal(Path, _, _)),
							 | 
						||
| 
								 | 
							
									    assert(journal(Path, append, Stream)),
							 | 
						||
| 
								 | 
							
									    journal_open(resume, T),
							 | 
						||
| 
								 | 
							
									    journal(Term)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								journal(Term) :-
							 | 
						||
| 
								 | 
							
									(   journal(_, _, Stream)
							 | 
						||
| 
								 | 
							
									->  write_journal(Term, Stream),
							 | 
						||
| 
								 | 
							
									    flush_output(Stream)
							 | 
						||
| 
								 | 
							
									;   broadcast(rdf_no_journal(Term))
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								write_journal(commit(TID, Time), Stream) :- !,
							 | 
						||
| 
								 | 
							
									format(Stream, 'commit(~q, ~2f).~n~n', [TID, Time]).
							 | 
						||
| 
								 | 
							
								write_journal(Term, Stream) :-
							 | 
						||
| 
								 | 
							
									format(Stream, '~q.~n', [Term]).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	rdfe_replay_journal(+File)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Replay a journal file. For now  this   is  our cheap way to deal
							 | 
						||
| 
								 | 
							
								%	with save/load. Future versions may be  more clever when dealing
							 | 
						||
| 
								 | 
							
								%	with the version information stored in the journal.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								rdfe_replay_journal(File) :-
							 | 
						||
| 
								 | 
							
									absolute_file_name(File,
							 | 
						||
| 
								 | 
							
											   [ extensions([rdfj, '']),
							 | 
						||
| 
								 | 
							
											     access(read)
							 | 
						||
| 
								 | 
							
											   ],
							 | 
						||
| 
								 | 
							
											   Path),
							 | 
						||
| 
								 | 
							
									open(Path, read, Stream),
							 | 
						||
| 
								 | 
							
									replay(Stream),
							 | 
						||
| 
								 | 
							
									close(Stream).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								replay(Stream) :-
							 | 
						||
| 
								 | 
							
									read(Stream, Term),
							 | 
						||
| 
								 | 
							
									replay(Term, Stream).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								replay(end_of_file, _) :- !.
							 | 
						||
| 
								 | 
							
								replay(start(_Attributes), Stream) :- !,
							 | 
						||
| 
								 | 
							
									read(Stream, Term),
							 | 
						||
| 
								 | 
							
									replay(Term, Stream).
							 | 
						||
| 
								 | 
							
								replay(resume(_Attributes), Stream) :- !,
							 | 
						||
| 
								 | 
							
									read(Stream, Term),
							 | 
						||
| 
								 | 
							
									replay(Term, Stream).
							 | 
						||
| 
								 | 
							
								replay(end(_Attributes), Stream) :- !,
							 | 
						||
| 
								 | 
							
									read(Stream, Term),
							 | 
						||
| 
								 | 
							
									replay(Term, Stream).
							 | 
						||
| 
								 | 
							
								replay(Term0, Stream) :-
							 | 
						||
| 
								 | 
							
									replay_transaction(Term0, Stream),
							 | 
						||
| 
								 | 
							
									read(Stream, Term),
							 | 
						||
| 
								 | 
							
									replay(Term, Stream).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								replay_transaction(Term0, Stream) :-
							 | 
						||
| 
								 | 
							
									collect_transaction(Term0, Stream, Transaction, Last),
							 | 
						||
| 
								 | 
							
									(   committed_transaction(Last)
							 | 
						||
| 
								 | 
							
									->  replay_actions(Transaction)
							 | 
						||
| 
								 | 
							
									;   true
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								collect_transaction(End, _, [], End) :-
							 | 
						||
| 
								 | 
							
									ends_transaction(End), !.
							 | 
						||
| 
								 | 
							
								collect_transaction(A, Stream, [A|T], End) :-
							 | 
						||
| 
								 | 
							
									read(Stream, Term),
							 | 
						||
| 
								 | 
							
									collect_transaction(Term, Stream, T, End).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								committed_transaction(commit(_)).
							 | 
						||
| 
								 | 
							
								committed_transaction(commit(_, _)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								ends_transaction(end_of_file).
							 | 
						||
| 
								 | 
							
								ends_transaction(commit(_)).
							 | 
						||
| 
								 | 
							
								ends_transaction(commit(_, _)).
							 | 
						||
| 
								 | 
							
								ends_transaction(rollback(_)).
							 | 
						||
| 
								 | 
							
								ends_transaction(end(_)).
							 | 
						||
| 
								 | 
							
								ends_transaction(start(_)).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								replay_actions([]).
							 | 
						||
| 
								 | 
							
								replay_actions([H|T]) :-
							 | 
						||
| 
								 | 
							
									(   replay_action(H)
							 | 
						||
| 
								 | 
							
									->  replay_actions(T)
							 | 
						||
| 
								 | 
							
									;   print_message(warning,
							 | 
						||
| 
								 | 
							
											  rdf_replay_failed(H)),
							 | 
						||
| 
								 | 
							
									    (	debugging(journal)
							 | 
						||
| 
								 | 
							
									    ->	gtrace,
							 | 
						||
| 
								 | 
							
										replay_actions([H|T])
							 | 
						||
| 
								 | 
							
									    ;	replay_actions(T)
							 | 
						||
| 
								 | 
							
									    )
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	replay_action(+Action)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Replay actions from the journal. Tricky is rdf_load/3. It should
							 | 
						||
| 
								 | 
							
								%	reload the file in the state it  was   in  at  the moment it was
							 | 
						||
| 
								 | 
							
								%	created. For now this has been hacked  for files that were empry
							 | 
						||
| 
								 | 
							
								%	at the moment they where loaded (e.g. created from `new_file' in
							 | 
						||
| 
								 | 
							
								%	our GUI prototype). How to solve this? We could warn if the file
							 | 
						||
| 
								 | 
							
								%	appears changed, but this isn't really   easy  as copying and OS
							 | 
						||
| 
								 | 
							
								%	differences makes it hard to decide on changes by length as well
							 | 
						||
| 
								 | 
							
								%	as modification time. Alternatively we could   save the state in
							 | 
						||
| 
								 | 
							
								%	seperate quick-load states.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								replay_action(retract(_, Subject, Predicate, Object, PayLoad)) :-
							 | 
						||
| 
								 | 
							
									rdf_retractall(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								replay_action(assert(_, Subject, Predicate, Object, PayLoad)) :-
							 | 
						||
| 
								 | 
							
									rdf_assert(Subject, Predicate, Object, PayLoad).
							 | 
						||
| 
								 | 
							
								replay_action(update(_, Subject, Predicate, Object, Action)) :-
							 | 
						||
| 
								 | 
							
									rdf_update(Subject, Predicate, Object, Action).
							 | 
						||
| 
								 | 
							
								replay_action(update(_, Subject, Predicate, Object, Payload, Action)) :-
							 | 
						||
| 
								 | 
							
									rdf_update(Subject, Predicate, Object, Payload, Action).
							 | 
						||
| 
								 | 
							
								replay_action(rdf_load(_, File, Options)) :-
							 | 
						||
| 
								 | 
							
									memberchk(md5(MD5), Options),
							 | 
						||
| 
								 | 
							
									snapshot_file(File, MD5,
							 | 
						||
| 
								 | 
							
										      [ access(read),
							 | 
						||
| 
								 | 
							
											file_errors(fail)
							 | 
						||
| 
								 | 
							
										      ],
							 | 
						||
| 
								 | 
							
										      Path), !,
							 | 
						||
| 
								 | 
							
									debug(snapshot, 'Reloading snapshot ~w~n', [Path]),
							 | 
						||
| 
								 | 
							
									load_snapshot(File, Path).
							 | 
						||
| 
								 | 
							
								replay_action(rdf_load(_, File, Options)) :-
							 | 
						||
| 
								 | 
							
									find_file(File, Options, Path),
							 | 
						||
| 
								 | 
							
									(   memberchk(triples(0), Options),
							 | 
						||
| 
								 | 
							
									    memberchk(modified(Modified), Options)
							 | 
						||
| 
								 | 
							
									->  rdf_retractall(_,_,_,Path:_),
							 | 
						||
| 
								 | 
							
									    retractall(rdf_db:rdf_source(Path, _, _, _)),	% TBD: move
							 | 
						||
| 
								 | 
							
									    rdf_md5(Path, MD5),
							 | 
						||
| 
								 | 
							
									    assert(rdf_db:rdf_source(Path, Modified, 0, MD5))
							 | 
						||
| 
								 | 
							
									;   rdf_load(Path)
							 | 
						||
| 
								 | 
							
									).
							 | 
						||
| 
								 | 
							
								replay_action(rdf_unload(_, Source)) :-
							 | 
						||
| 
								 | 
							
									rdf_unload(Source).
							 | 
						||
| 
								 | 
							
								replay_action(ns(_, register(ID, URI))) :- !,
							 | 
						||
| 
								 | 
							
									rdf_register_ns(ID, URI).
							 | 
						||
| 
								 | 
							
								replay_action(ns(_, unregister(ID, URI))) :-
							 | 
						||
| 
								 | 
							
									retractall(rdf_db:ns(ID, URI)).
							 | 
						||
| 
								 | 
							
								replay_action(watermark(_, _Name)) :-
							 | 
						||
| 
								 | 
							
									true.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								find_file(File, _, File) :-
							 | 
						||
| 
								 | 
							
									exists_file(File), !.
							 | 
						||
| 
								 | 
							
								find_file(File, Options, Path) :-
							 | 
						||
| 
								 | 
							
									memberchk(pwd(PWD), Options),
							 | 
						||
| 
								 | 
							
									make_path(File, PWD, Path),
							 | 
						||
| 
								 | 
							
									exists_file(Path), !.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%%	make_path(+File, +PWD, -Path)
							 | 
						||
| 
								 | 
							
								%
							 | 
						||
| 
								 | 
							
								%	Return location of File relative to PWD, Parent of PWD, etc. (TBD)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								make_path(File, PWD, Path) :-
							 | 
						||
| 
								 | 
							
									atom_concat(PWD, /, PWD2),
							 | 
						||
| 
								 | 
							
									atom_concat(PWD2, Path, File).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										 /*******************************
							 | 
						||
| 
								 | 
							
										 *	      MESSAGES		*
							 | 
						||
| 
								 | 
							
										 *******************************/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								:- multifile
							 | 
						||
| 
								 | 
							
									prolog:message/3,
							 | 
						||
| 
								 | 
							
									user:message_hook/3.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								%	Catch messages.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								prolog:message(rdf_replay_failed(Term)) -->
							 | 
						||
| 
								 | 
							
									[ 'RDFDB: Replay of ~p failed'-[Term] ].
							 | 
						||
| 
								 | 
							
								prolog:message(rdf_undo_failed(Term)) -->
							 | 
						||
| 
								 | 
							
									[ 'RDFDB: Undo of ~p failed'-[Term] ].
							 |