001: /*****************************************************************************
002: * Source code information
003: * -----------------------
004: * Original author Ian Dickinson, HP Labs Bristol
005: * Author email ian.dickinson@hp.com
006: * Package Jena 2
007: * Web http://sourceforge.net/projects/jena/
008: * Created 10-Sep-2003
009: * Filename $RCSfile: OntEventManager.java,v $
010: * Revision $Revision: 1.9 $
011: * Release status $State: Exp $
012: *
013: * Last modified on $Date: 2008/01/02 12:10:36 $
014: * by $Author: andy_seaborne $
015: *
016: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
017: * [See end of file]
018: *****************************************************************************/package com.hp.hpl.jena.ontology.event;
019:
020: // Imports
021: ///////////////
022: import java.util.*;
023:
024: import com.hp.hpl.jena.ontology.*;
025: import com.hp.hpl.jena.rdf.listeners.StatementListener;
026: import com.hp.hpl.jena.rdf.model.*;
027: import com.hp.hpl.jena.vocabulary.*;
028: import com.hp.hpl.jena.vocabulary.OntEventsVocab;
029:
030: /**
031: * <p>
032: * An adapter that translates RDF model-level changes into higher level changes that
033: * are appropriate to ontology users. The large number of specific events that the
034: * ontology model can produce makes the traditional Java style of listener interface
035: * impractical. Instead, this event manager allows the user to register
036: * {@linkplain OntEventHandler handlers}, based on command pattern, against specific
037: * {@linkplain OntEventsVocab event types}.
038: * </p>
039: * <p>
040: * For example, to register a handler for the declaration of an ontology class:
041: * </p>
042: * <pre>
043: * OntModel m = ...
044: * OntEventManager em = m.getEventManager();
045: * em.addHandler( OntEvents.CLASS_DECLARATION,
046: * new OntEventHandler() {
047: * public void action( Resource ev, boolean added,
048: * RDFNode arg0, RDFNode arg1 ) {
049: * OntClass c = (OntClass) arg0;
050: * if (added) {
051: * // class c added to model
052: * }
053: * else {
054: * // class c removed from model
055: * }
056: * }
057: * }
058: * );
059: * </pre>
060: * <p>
061: * This listener acts as an adapter for graph events (i.e. adding and
062: * removing triples), converting them to higher-level ontology events. This is non-trivial, because
063: * Jena currently doesn't have a means of batching changes so that only consistent
064: * graph states are seen. For efficiency in non event-using models, this listener
065: * is only attached as a statement listener to the underlying graph when the first
066: * ontology event listener is added.
067: * </p>
068: *
069: * @author Ian Dickinson, HP Labs
070: * (<a href="mailto:Ian.Dickinson@hp.com" >email</a>)
071: * @version CVS $Id: OntEventManager.java,v 1.9 2008/01/02 12:10:36 andy_seaborne Exp $
072: */
073: public class OntEventManager extends StatementListener {
074: // Constants
075: //////////////////////////////////
076:
077: // Static variables
078: //////////////////////////////////
079:
080: /** Initialisation data for the rdf:type to event type table */
081: private static Object[][] s_rdfTypeInit = {
082: { OntEventsVocab.classDeclaration, new ProfileAccessor() {
083: public Resource get(Profile p) {
084: return p.CLASS();
085: }
086: } },
087: { OntEventsVocab.datarangeDeclaration,
088: new ProfileAccessor() {
089: public Resource get(Profile p) {
090: return p.DATARANGE();
091: }
092: } },
093: { OntEventsVocab.propertyDeclaration,
094: new ProfileAccessor() {
095: public Resource get(Profile p) {
096: return p.PROPERTY();
097: }
098: } },
099: { OntEventsVocab.objectPropertyDeclaration,
100: new ProfileAccessor() {
101: public Resource get(Profile p) {
102: return p.OBJECT_PROPERTY();
103: }
104: } },
105: { OntEventsVocab.datatypePropertyDeclaration,
106: new ProfileAccessor() {
107: public Resource get(Profile p) {
108: return p.DATATYPE_PROPERTY();
109: }
110: } },
111: { OntEventsVocab.transitivePropertyDeclaration,
112: new ProfileAccessor() {
113: public Resource get(Profile p) {
114: return p.TRANSITIVE_PROPERTY();
115: }
116: } },
117: { OntEventsVocab.symmetricPropertyDeclaration,
118: new ProfileAccessor() {
119: public Resource get(Profile p) {
120: return p.SYMMETRIC_PROPERTY();
121: }
122: } },
123: { OntEventsVocab.functionalPropertyDeclaration,
124: new ProfileAccessor() {
125: public Resource get(Profile p) {
126: return p.FUNCTIONAL_PROPERTY();
127: }
128: } },
129: { OntEventsVocab.inverseFunctionalPropertyDeclaration,
130: new ProfileAccessor() {
131: public Resource get(Profile p) {
132: return p.INVERSE_FUNCTIONAL_PROPERTY();
133: }
134: } },
135: { OntEventsVocab.annotationPropertyDeclaration,
136: new ProfileAccessor() {
137: public Resource get(Profile p) {
138: return p.ANNOTATION_PROPERTY();
139: }
140: } },
141: { OntEventsVocab.ontologyPropertyDeclaration,
142: new ProfileAccessor() {
143: public Resource get(Profile p) {
144: return p.ONTOLOGY_PROPERTY();
145: }
146: } },
147: { OntEventsVocab.restrictionDeclaration,
148: new ProfileAccessor() {
149: public Resource get(Profile p) {
150: return p.RESTRICTION();
151: }
152: } },
153: { OntEventsVocab.allDifferentDeclaration,
154: new ProfileAccessor() {
155: public Resource get(Profile p) {
156: return p.ALL_DIFFERENT();
157: }
158: } },
159: { OntEventsVocab.ontologyDeclaration,
160: new ProfileAccessor() {
161: public Resource get(Profile p) {
162: return p.ONTOLOGY();
163: }
164: } }, };
165:
166: /** Initialisation data for the predicate to event type table */
167: private static Object[][] s_predicateInit = {
168: { OntEventsVocab.intersectionOf, new ProfileAccessor() {
169: public Resource get(Profile p) {
170: return p.INTERSECTION_OF();
171: }
172: } },
173: { OntEventsVocab.equivalentClass, new ProfileAccessor() {
174: public Resource get(Profile p) {
175: return p.EQUIVALENT_CLASS();
176: }
177: } },
178: { OntEventsVocab.disjointWith, new ProfileAccessor() {
179: public Resource get(Profile p) {
180: return p.DISJOINT_WITH();
181: }
182: } },
183: { OntEventsVocab.equivalentProperty, new ProfileAccessor() {
184: public Resource get(Profile p) {
185: return p.EQUIVALENT_PROPERTY();
186: }
187: } },
188: { OntEventsVocab.sameAs, new ProfileAccessor() {
189: public Resource get(Profile p) {
190: return p.SAME_AS();
191: }
192: } },
193: { OntEventsVocab.differentFrom, new ProfileAccessor() {
194: public Resource get(Profile p) {
195: return p.DIFFERENT_FROM();
196: }
197: } },
198: { OntEventsVocab.distinctMembers, new ProfileAccessor() {
199: public Resource get(Profile p) {
200: return p.DISTINCT_MEMBERS();
201: }
202: } },
203: { OntEventsVocab.unionOf, new ProfileAccessor() {
204: public Resource get(Profile p) {
205: return p.UNION_OF();
206: }
207: } },
208: { OntEventsVocab.intersectionOf, new ProfileAccessor() {
209: public Resource get(Profile p) {
210: return p.INTERSECTION_OF();
211: }
212: } },
213: { OntEventsVocab.complementOf, new ProfileAccessor() {
214: public Resource get(Profile p) {
215: return p.COMPLEMENT_OF();
216: }
217: } },
218: { OntEventsVocab.oneOf, new ProfileAccessor() {
219: public Resource get(Profile p) {
220: return p.ONE_OF();
221: }
222: } },
223: { OntEventsVocab.onProperty, new ProfileAccessor() {
224: public Resource get(Profile p) {
225: return p.ON_PROPERTY();
226: }
227: } },
228: { OntEventsVocab.allValuesFrom, new ProfileAccessor() {
229: public Resource get(Profile p) {
230: return p.ALL_VALUES_FROM();
231: }
232: } },
233: { OntEventsVocab.hasValue, new ProfileAccessor() {
234: public Resource get(Profile p) {
235: return p.HAS_VALUE();
236: }
237: } },
238: { OntEventsVocab.someValuesFrom, new ProfileAccessor() {
239: public Resource get(Profile p) {
240: return p.SOME_VALUES_FROM();
241: }
242: } },
243: { OntEventsVocab.minCardinality, new ProfileAccessor() {
244: public Resource get(Profile p) {
245: return p.MIN_CARDINALITY();
246: }
247: } },
248: { OntEventsVocab.maxCardinality, new ProfileAccessor() {
249: public Resource get(Profile p) {
250: return p.MAX_CARDINALITY();
251: }
252: } },
253: { OntEventsVocab.cardinalityQ, new ProfileAccessor() {
254: public Resource get(Profile p) {
255: return p.CARDINALITY_Q();
256: }
257: } },
258: { OntEventsVocab.minCardinalityQ, new ProfileAccessor() {
259: public Resource get(Profile p) {
260: return p.MIN_CARDINALITY_Q();
261: }
262: } },
263: { OntEventsVocab.maxCardinalityQ, new ProfileAccessor() {
264: public Resource get(Profile p) {
265: return p.MAX_CARDINALITY_Q();
266: }
267: } },
268: { OntEventsVocab.cardinality, new ProfileAccessor() {
269: public Resource get(Profile p) {
270: return p.CARDINALITY();
271: }
272: } },
273: { OntEventsVocab.inverseOf, new ProfileAccessor() {
274: public Resource get(Profile p) {
275: return p.INVERSE_OF();
276: }
277: } },
278: { OntEventsVocab.imports, new ProfileAccessor() {
279: public Resource get(Profile p) {
280: return p.IMPORTS();
281: }
282: } },
283: { OntEventsVocab.versionInfo, new ProfileAccessor() {
284: public Resource get(Profile p) {
285: return p.VERSION_INFO();
286: }
287: } },
288: { OntEventsVocab.priorVersion, new ProfileAccessor() {
289: public Resource get(Profile p) {
290: return p.PRIOR_VERSION();
291: }
292: } },
293: { OntEventsVocab.backwardCompatibleWith,
294: new ProfileAccessor() {
295: public Resource get(Profile p) {
296: return p.BACKWARD_COMPATIBLE_WITH();
297: }
298: } },
299: { OntEventsVocab.incompatibleWith, new ProfileAccessor() {
300: public Resource get(Profile p) {
301: return p.INCOMPATIBLE_WITH();
302: }
303: } }, };
304:
305: // Instance variables
306: //////////////////////////////////
307:
308: /** Map from event types to handlers */
309: private Map m_handlers = new HashMap();
310:
311: /** Map from rdf:type to event type */
312: private Map m_rdfTypeToEventType = new HashMap();
313:
314: /** Map from predicate to event type */
315: private Map m_predicateToEventType = new HashMap();
316:
317: /** Default event handler */
318: private OntEventHandler m_defaultHandler = null;
319:
320: // Constructors
321: //////////////////////////////////
322:
323: /**
324: * <p>Construct an ontology event manager for the given ontology model.
325: * This involves registering adapters for the ontology events corresponding
326: * to the language profile of the given model.</p>
327: * @param m An ontology model
328: */
329: public OntEventManager(OntModel m) {
330: Profile p = m.getProfile();
331: initialiseTable(m_rdfTypeToEventType, p, s_rdfTypeInit);
332: initialiseTable(m_predicateToEventType, p, s_predicateInit);
333: }
334:
335: // External signature methods
336: //////////////////////////////////
337:
338: /**
339: * <p>Handle the addition of a statement to the model.</p>
340: * @param s The added statement
341: */
342: public void addedStatement(Statement s) {
343: processStatement(s, true);
344: }
345:
346: /**
347: * <p>Handle the removal of a statement to the model</p>
348: * @param s The removed statement
349: */
350: public void removedStatement(Statement s) {
351: processStatement(s, false);
352: }
353:
354: /**
355: * <p>Raise an event to be handled by the attached event handlers.</p>
356: * @param event The resource representing the event type
357: * @param added True if this is an addition to the model, false otherwise
358: * @param source The model that caused the event to be raised
359: * @param arg0 The first argument to the event
360: * @param arg1 The second argument to the event, or null
361: * @param arg2 The third argument to the event, or null
362: */
363: public void raise(Resource event, boolean added, Model source,
364: RDFNode arg0, RDFNode arg1, RDFNode arg2) {
365: OntEventHandler h = getHandler(event);
366: if (h != null) {
367: h.action(event, added, source, arg0, arg1, arg2);
368: } else if (m_defaultHandler != null) {
369: // if no assigned handler, call the default handler
370: m_defaultHandler.action(event, added, source, arg0, arg1,
371: arg2);
372: }
373: }
374:
375: /**
376: * <p>Add the given handler as the default event handler, which will be invoked if
377: * no other handler is applicable to a given event.</p>
378: * @param handler The event handler object
379: */
380: public void addDefaultHandler(OntEventHandler handler) {
381: m_defaultHandler = handler;
382: }
383:
384: /**
385: * <p>Add the given handler as the handler for the given event type, replacing
386: * any existing handler.</p>
387: * @param event The event type to be handled, as a resource
388: * @param handler The event handler object
389: */
390: public void addHandler(Resource event, OntEventHandler handler) {
391: m_handlers.put(event, handler);
392: }
393:
394: /**
395: * <p>Add the given handlers as the handler for the given event types, replacing
396: * any existing handlers.</p>
397: * @param handlers An array of pairs, where the first element of each pair
398: * is the resource denoting the event to be handled, and the second is the
399: * handler object
400: */
401: public void addHandlers(Object[][] handlers) {
402: for (int i = 0; i < handlers.length;) {
403: Resource r = (Resource) handlers[i][0];
404: OntEventHandler h = (OntEventHandler) handlers[i][1];
405: addHandler(r, h);
406: }
407: }
408:
409: /**
410: * <p>Answer the event handler for the given event, or null if not defined</p>
411: * @param event An event type to look up
412: * @return The current handler for the event, or null
413: */
414: public OntEventHandler getHandler(Resource event) {
415: return (OntEventHandler) m_handlers.get(event);
416: }
417:
418: /**
419: * <p>Answer the default event handler, or null if not defined</p>
420: * @return The default event handler, or null
421: */
422: public OntEventHandler getDefaultHandler() {
423: return m_defaultHandler;
424: }
425:
426: /**
427: * <p>Remove any existing handler for the given event type.</p>
428: * @param event The event for which the handler is to be removed
429: */
430: public void removeHandler(Resource event) {
431: m_handlers.remove(event);
432: }
433:
434: /**
435: * <p>Answer true if there is a defined handler for the given event type.</p>
436: * @param event An event type, as a resource
437: * @return True if there is a defined handler for the event
438: */
439: public boolean hasHandler(Resource event) {
440: return m_handlers.containsKey(event);
441: }
442:
443: /**
444: * <p>Answer an iterator over the events that are registered in this
445: * event manager.</p>
446: * @return An iterator over the event types of events that have registered handlers
447: */
448: public Iterator listRegisteredEvents() {
449: return m_handlers.keySet().iterator();
450: }
451:
452: // Internal implementation methods
453: //////////////////////////////////
454:
455: /**
456: * <p>Initialise the given map from static initialisation data. This will be a mapping
457: * that allows us to determine the correct ontology event type for a given triple.</p>
458: * @param map The map to update
459: * @param p An ontology language profile
460: * @param source A table of initialisation data
461: */
462: private void initialiseTable(Map map, Profile p, Object[][] source) {
463: for (int i = 0; i < source.length; i++) {
464: // get the initialisation data from the table
465: Resource evType = (Resource) source[i][0];
466: Resource key = ((ProfileAccessor) source[i][1]).get(p);
467:
468: if (key != null) {
469: // is defined for this term
470: map.put(key, evType);
471: }
472: }
473: }
474:
475: /**
476: * <p>Process an incoming added or removed statement to raise the appropriate ontology event.</p>
477: * @param s
478: * @param added
479: */
480: private void processStatement(Statement s, boolean added) {
481: // first check if this an rdf:type statement
482: if (s.getPredicate().equals(RDF.type)) {
483: // yes - now is it a builtin type?
484: Resource type = s.getResource();
485: Resource evType = (Resource) m_rdfTypeToEventType.get(type);
486:
487: if (evType != null) {
488: // was a known type, so we know which event to raise
489: raise(evType, added, s.getModel(), s.getSubject(),
490: null, null);
491: } else {
492: // must be an individual
493: raise(OntEventsVocab.individualDeclaration, added, s
494: .getModel(), s.getSubject(), type, null);
495: }
496: } else {
497: // not rdf:type, but may still be a known predicate
498: Property pred = s.getPredicate();
499: Resource evType = (Resource) m_predicateToEventType
500: .get(pred);
501:
502: if (evType != null) {
503: // was a known predicate, so we know which event to raise
504: raise(evType, added, s.getModel(), s.getSubject(), s
505: .getObject(), null);
506: } else {
507: // default - assume user data
508: raise(OntEventsVocab.userData, added, s.getModel(), s
509: .getSubject(), pred, s.getObject());
510: }
511: }
512: }
513:
514: //==============================================================================
515: // Inner class definitions
516: //==============================================================================
517:
518: /** Simple wrapper to allow us to dynamically extract elements from the profile */
519: private static interface ProfileAccessor {
520: public Resource get(Profile p);
521: }
522: }
523:
524: /*
525: * (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
526: * All rights reserved.
527: *
528: * Redistribution and use in source and binary forms, with or without
529: * modification, are permitted provided that the following conditions
530: * are met:
531: * 1. Redistributions of source code must retain the above copyright
532: * notice, this list of conditions and the following disclaimer.
533: * 2. Redistributions in binary form must reproduce the above copyright
534: * notice, this list of conditions and the following disclaimer in the
535: * documentation and/or other materials provided with the distribution.
536: * 3. The name of the author may not be used to endorse or promote products
537: * derived from this software without specific prior written permission.
538: *
539: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
540: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
541: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
542: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
543: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
544: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
545: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
546: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
547: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
548: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
549: */
|