/*
* #!
* Ontopia Engine
* #-
* Copyright (C) 2001 - 2013 The Ontopia Project
* #-
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* !#
*/
package net.ontopia.topicmaps.impl.utils;
import java.util.Iterator;
import java.util.Map;
import net.ontopia.infoset.core.LocatorIF;
import net.ontopia.topicmaps.core.AssociationIF;
import net.ontopia.topicmaps.core.AssociationRoleIF;
import net.ontopia.topicmaps.core.ConstraintViolationException;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.TMObjectIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicNameIF;
import net.ontopia.topicmaps.core.UniquenessViolationException;
import net.ontopia.topicmaps.core.VariantNameIF;
/**
* INTERNAL: Class that maintains indexes for use with the TopicMapIF locator
* lookup methods. This is especially useful in the cases where the topic map
* object cannot use queries to do the lookups.
* </p>
*
* This class uses the event model to maintain its indexes.
* </p>
*/
public abstract class AbstractSubjectIdentityCache implements EventListenerIF,
java.io.Serializable {
protected Map<String, EventHandler> handlers;
public AbstractSubjectIdentityCache(Map<String, EventHandler> handlers) {
this.handlers = handlers;
}
/**
* INTERNAL: Registers the subject identity cache listeners with the default
* event manager and the object tree event managers.
*
* @param emanager The default event manager.
* @param otree The object tree manager.
*/
public void registerListeners(EventManagerIF emanager, EventManagerIF otree) {
// Initialize object tree event handlers [objects added or removed]
otree.addListener(new TopicAddedHandler(), TopicIF.EVENT_ADDED);
otree.addListener(new TopicRemovedHandler(), TopicIF.EVENT_REMOVED);
EventHandler oah = new TMObjectAddedHandler();
EventHandler orh = new TMObjectRemovedHandler();
otree.addListener(oah, AssociationIF.EVENT_ADDED);
otree.addListener(orh, AssociationIF.EVENT_REMOVED);
otree.addListener(oah, AssociationRoleIF.EVENT_ADDED);
otree.addListener(orh, AssociationRoleIF.EVENT_REMOVED);
otree.addListener(oah, TopicNameIF.EVENT_ADDED);
otree.addListener(orh, TopicNameIF.EVENT_REMOVED);
otree.addListener(oah, OccurrenceIF.EVENT_ADDED);
otree.addListener(orh, OccurrenceIF.EVENT_REMOVED);
otree.addListener(oah, VariantNameIF.EVENT_ADDED);
otree.addListener(orh, VariantNameIF.EVENT_REMOVED);
// Initialize object property event handlers
handlers.put(TopicIF.EVENT_ADD_SUBJECTLOCATOR, new TopicIF_addSubjectLocator());
handlers.put(TopicIF.EVENT_REMOVE_SUBJECTLOCATOR, new TopicIF_removeSubjectLocator());
handlers.put(TopicIF.EVENT_ADD_SUBJECTIDENTIFIER, new TopicIF_addSubjectIdentifier());
handlers.put(TopicIF.EVENT_REMOVE_SUBJECTIDENTIFIER, new TopicIF_removeSubjectIdentifier());
handlers.put(TMObjectIF.EVENT_ADD_ITEMIDENTIFIER, new TMObjectIF_addItemIdentifier());
handlers.put(TMObjectIF.EVENT_REMOVE_ITEMIDENTIFIER, new TMObjectIF_removeItemIdentifier());
// Register as event listener
Iterator<String> iter = handlers.keySet().iterator();
while (iter.hasNext()) {
emanager.addListener(this, iter.next());
}
}
// -----------------------------------------------------------------------------
// TopicMapIF locator lookup methods
// -----------------------------------------------------------------------------
public abstract TMObjectIF getObjectById(String object_id);
public abstract TMObjectIF getObjectByItemIdentifier(LocatorIF locator);
public abstract TopicIF getTopicBySubjectLocator(LocatorIF locator);
public abstract TopicIF getTopicBySubjectIdentifier(LocatorIF locator);
// -----------------------------------------------------------------------------
// Object registration methods
// -----------------------------------------------------------------------------
/**
* INTERNAL: Register the object with the identity map. Does nothing by
* default.
*/
protected void registerObject(TMObjectIF object) {
}
/**
* INTERNAL: Unregister the object with the identity map. Does nothing by
* default.
*/
protected void unregisterObject(TMObjectIF object) {
}
// -----------------------------------------------------------------------------
// Event handler methods
// -----------------------------------------------------------------------------
protected abstract TMObjectIF _getObjectByItemIdentifier(LocatorIF source_locator);
protected abstract void registerSourceLocator(LocatorIF source_locator,
TMObjectIF object);
protected abstract void unregisterSourceLocator(LocatorIF source_locator);
protected abstract TopicIF _getTopicBySubjectIdentifier(LocatorIF subject_indicator);
protected abstract void registerSubjectIndicator(LocatorIF subject_indicator,
TopicIF object);
protected abstract void unregisterSubjectIndicator(LocatorIF subject_indicator);
protected abstract TopicIF _getTopicBySubjectLocator(LocatorIF subject);
protected abstract void registerSubject(LocatorIF subject, TopicIF object);
protected abstract void unregisterSubject(LocatorIF subject);
// -----------------------------------------------------------------------------
// EventListenerIF
// -----------------------------------------------------------------------------
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
if (handlers.containsKey(event)) {
handlers.get(event).processEvent(object, event, new_value, old_value);
}
}
// -----------------------------------------------------------------------------
// Event handlers
// -----------------------------------------------------------------------------
protected abstract class EventHandler implements EventListenerIF,
java.io.Serializable {
public abstract void processEvent(Object object, String event,
Object new_value, Object old_value);
protected void addEvent(Object object, String event, Object value) {
// if (!handlers.containsKey(event)) System.out.println("+event> " +
// event);
handlers.get(event).processEvent(object, event,
value, null);
}
protected void removeEvent(Object object, String event, Object value) {
// if (!handlers.containsKey(event)) System.out.println("-event> " +
// event);
handlers.get(event).processEvent(object, event, null, value);
}
}
/**
* EventHandler: TopicIF.added
*/
class TopicAddedHandler extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
TopicIF added = (TopicIF) new_value;
// Register object
registerObject(added);
// Add subject locators
Object[] subjects = added.getSubjectLocators().toArray();
for (int i = 0; i < subjects.length; i++)
addEvent(added, TopicIF.EVENT_ADD_SUBJECTLOCATOR, subjects[i]);
// Add indicators
Object[] indicators = added.getSubjectIdentifiers().toArray();
for (int i = 0; i < indicators.length; i++)
addEvent(added, TopicIF.EVENT_ADD_SUBJECTIDENTIFIER, indicators[i]);
// Add source locators
Object[] sources = added.getItemIdentifiers().toArray();
for (int i = 0; i < sources.length; i++)
addEvent(added, TMObjectIF.EVENT_ADD_ITEMIDENTIFIER, sources[i]);
}
}
/**
* EventHandler: TopicIF.removed
*/
class TopicRemovedHandler extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
TopicIF removed = (TopicIF) old_value;
// Remove subject locators
Object[] subjects = removed.getSubjectLocators().toArray();
for (int i = 0; i < subjects.length; i++)
removeEvent(removed, TopicIF.EVENT_REMOVE_SUBJECTLOCATOR, subjects[i]);
// Remove indicators
Object[] indicators = removed.getSubjectIdentifiers().toArray();
for (int i = 0; i < indicators.length; i++)
removeEvent(removed, TopicIF.EVENT_REMOVE_SUBJECTIDENTIFIER, indicators[i]);
// Remove source locators
Object[] sources = removed.getItemIdentifiers().toArray();
for (int i = 0; i < sources.length; i++)
removeEvent(removed, TMObjectIF.EVENT_REMOVE_ITEMIDENTIFIER, sources[i]);
// Unregister object
unregisterObject(removed);
}
}
/**
* EventHandler: TMObjectIF.added
*/
class TMObjectAddedHandler extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
TMObjectIF added = (TMObjectIF) new_value;
// Register object
registerObject(added);
// Add source locators
Object[] sources = added.getItemIdentifiers().toArray();
for (int i = 0; i < sources.length; i++)
addEvent(added, TMObjectIF.EVENT_ADD_ITEMIDENTIFIER, sources[i]);
}
}
/**
* EventHandler: TMObjectIF.removed
*/
class TMObjectRemovedHandler extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
TMObjectIF removed = (TMObjectIF) old_value;
// Remove source locators
Object[] sources = removed.getItemIdentifiers().toArray();
for (int i = 0; i < sources.length; i++)
removeEvent(removed, TMObjectIF.EVENT_REMOVE_ITEMIDENTIFIER, sources[i]);
// Unregister object
unregisterObject(removed);
}
}
/**
* EventHandler: TopicIF.addSubjectLocator
*/
class TopicIF_addSubjectLocator extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
// Check subject locator uniqueness
TopicIF existing = _getTopicBySubjectLocator((LocatorIF)new_value);
if (existing != null && existing != object)
throw new UniquenessViolationException("Another topic " + existing
+ " already has this subject locator: " + new_value + " ("
+ object + ")");
// Register new subject locator
registerSubject((LocatorIF)new_value, (TopicIF)object);
}
}
/**
* EventHandler: TopicIF.removeSubjectLocator
*/
class TopicIF_removeSubjectLocator extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
// Unregister subject locator
unregisterSubject((LocatorIF)old_value);
}
}
/**
* EventHandler: TopicIF.addSubjectIdentifier
*/
class TopicIF_addSubjectIdentifier extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
// Check indicator uniqueness
TopicIF existing = _getTopicBySubjectIdentifier((LocatorIF)new_value);
if (existing != null && existing != object)
throw new UniquenessViolationException("Another topic " + existing
+ " already has this subject identifier: " + new_value + " ("
+ object + ")");
// Check for source locator clash
TMObjectIF existing_tmo = _getObjectByItemIdentifier((LocatorIF)new_value);
if (existing_tmo != null && existing_tmo != object
&& (existing_tmo instanceof TopicIF))
throw new UniquenessViolationException("Another topic " + existing_tmo
+ " already has this subject identifier as its item identifier: "
+ new_value + " (" + object + ")");
// Register new subject indicator
registerSubjectIndicator((LocatorIF)new_value, (TopicIF)object);
}
}
/**
* EventHandler: TopicIF.removeSubjectIdentifier
*/
class TopicIF_removeSubjectIdentifier extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
// Unregister subject indicator
unregisterSubjectIndicator((LocatorIF)old_value);
}
}
/**
* EventHandler: TMObjectIF.addItemIdentifier
*/
class TMObjectIF_addItemIdentifier extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) throws ConstraintViolationException {
// Check source locator uniqueness
TMObjectIF existing = _getObjectByItemIdentifier((LocatorIF)new_value);
// NOTE: we should not get this far if existing == object,
// because we're checking for this in
// TMObject.addItemIdentifier(). If we get here it is often an
// indication of the database using case insensitive =
// comparisions.
if (existing != null && existing != object)
throw new UniquenessViolationException("Another object " + existing
+ " already has this item identifier: " + new_value + " (" + object
+ ") " + (existing == object));
// Check for subject identifier clash
existing = _getTopicBySubjectIdentifier((LocatorIF)new_value);
if (existing != null && existing != object && (object instanceof TopicIF))
throw new UniquenessViolationException("Another topic " + existing
+ " already has this item identifier as its subject identifier: "
+ new_value + " (" + object + ")");
// Register new source locator
registerSourceLocator((LocatorIF)new_value, (TMObjectIF)object);
}
}
/**
* EventHandler: TMObjectIF.removeItemIdentifier
*/
class TMObjectIF_removeItemIdentifier extends EventHandler {
public void processEvent(Object object, String event, Object new_value,
Object old_value) {
// Unregister source locator
unregisterSourceLocator((LocatorIF)old_value);
}
}
}