From: <lh...@us...> - 2008-04-21 14:59:07
|
Revision: 26 http://tinytim.svn.sourceforge.net/tinytim/?rev=26&view=rev Author: lheuer Date: 2008-04-21 07:59:01 -0700 (Mon, 21 Apr 2008) Log Message: ----------- - Initial import of the core and some indexes - CopyUtils is not ready yet Modified Paths: -------------- tinytim/trunk/src/main/java/org/tinytim/TopicUtils.java tinytim/trunk/src/main/java/org/tinytim/index/IndexFlagsImpl.java Added Paths: ----------- tinytim/trunk/src/main/java/org/tinytim/AssociationImpl.java tinytim/trunk/src/main/java/org/tinytim/AssociationRoleImpl.java tinytim/trunk/src/main/java/org/tinytim/CopyUtils.java tinytim/trunk/src/main/java/org/tinytim/DatatypeAwareConstruct.java tinytim/trunk/src/main/java/org/tinytim/IDatatypeAwareConstruct.java tinytim/trunk/src/main/java/org/tinytim/IdentityManager.java tinytim/trunk/src/main/java/org/tinytim/MergeUtils.java tinytim/trunk/src/main/java/org/tinytim/OccurrenceImpl.java tinytim/trunk/src/main/java/org/tinytim/TopicImpl.java tinytim/trunk/src/main/java/org/tinytim/TopicNameImpl.java tinytim/trunk/src/main/java/org/tinytim/VariantImpl.java tinytim/trunk/src/main/java/org/tinytim/index/IndexManager.java tinytim/trunk/src/main/java/org/tinytim/index/ScopedIndex.java tinytim/trunk/src/main/java/org/tinytim/index/TypeInstanceIndex.java Added: tinytim/trunk/src/main/java/org/tinytim/AssociationImpl.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/AssociationImpl.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/AssociationImpl.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,133 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Set; + +import org.tmapi.core.Association; +import org.tmapi.core.AssociationRole; +import org.tmapi.core.TMAPIException; +import org.tmapi.core.Topic; + +/** + * {@link org.tmapi.core.Association} implementation. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +public final class AssociationImpl extends Scoped implements Association, + IReifiable, ITyped, IScoped { + + private Set<AssociationRole> _roles; + private Topic _type; + + AssociationImpl(TopicMapImpl topicMap) { + super(topicMap, null); + _roles = topicMap.getCollectionFactory().createSet(2); + } + + /** + * Adds a role to this association. + * + * @param role The role to add. + */ + void addRole(AssociationRole role) { + AssociationRoleImpl r = (AssociationRoleImpl) role; + if (r._parent == this) { + return; + } + assert r._parent == null; + _fireEvent(Event.ADD_ROLE, null, r); + _roles.add(r); + r._parent = this; + TopicImpl player = (TopicImpl) r.getPlayer(); + if (player != null) { + player.addRolePlayed(r); + } + } + + /** + * Removes a role from this association. + * + * @param role The role to remove. + */ + void removeRole(AssociationRole role) { + AssociationRoleImpl r = (AssociationRoleImpl) role; + if (r._parent != this) { + return; + } + _fireEvent(Event.REMOVE_ROLE, r, null); + _roles.remove(role); + r._parent = null; + TopicImpl player = (TopicImpl) r.getPlayer(); + if (player != null) { + player.removeRolePlayed(r); + } + } + + /* (non-Javadoc) + * @see org.tmapi.core.Association#createAssociationRole(org.tmapi.core.Topic, org.tmapi.core.Topic) + */ + public AssociationRole createAssociationRole(Topic player, Topic type) { + AssociationRoleImpl role = new AssociationRoleImpl(_tm, type, player); + addRole(role); + return role; + } + + /* (non-Javadoc) + * @see org.tmapi.core.Association#getAssociationRoles() + */ + public Set<AssociationRole> getAssociationRoles() { + return Collections.unmodifiableSet(_roles); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Association#getType() + */ + public Topic getType() { + return _type; + } + + /* (non-Javadoc) + * @see org.tmapi.core.Association#setType(org.tmapi.core.Topic) + */ + public void setType(Topic type) { + if (_type == type) { + return; + } + _fireEvent(Event.SET_TYPE, _type, type); + _type = type; + } + + /* (non-Javadoc) + * @see org.tmapi.core.TopicMapObject#remove() + */ + public void remove() throws TMAPIException { + _tm.removeAssociation(this); + for (AssociationRole role: new ArrayList<AssociationRole>(_roles)) { + role.remove(); + } + _roles = null; + super.dispose(); + } +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/AssociationImpl.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/AssociationRoleImpl.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/AssociationRoleImpl.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/AssociationRoleImpl.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,83 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import org.tmapi.core.Association; +import org.tmapi.core.AssociationRole; +import org.tmapi.core.TMAPIException; +import org.tmapi.core.Topic; + +/** + * {@link org.tmapi.core.AssociationRole} implementation. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +public final class AssociationRoleImpl extends Typed implements AssociationRole, + ITyped { + + private Topic _player; + + AssociationRoleImpl(TopicMapImpl tm, Topic type, Topic player) { + super(tm, type, null); + _player = player; + } + + /* (non-Javadoc) + * @see org.tmapi.core.AssociationRole#getAssociation() + */ + public Association getAssociation() { + return (Association) _parent; + } + + /* (non-Javadoc) + * @see org.tmapi.core.AssociationRole#getPlayer() + */ + public Topic getPlayer() { + return _player; + } + + /* (non-Javadoc) + * @see org.tmapi.core.AssociationRole#setPlayer(org.tmapi.core.Topic) + */ + public void setPlayer(Topic player) { + if (_player == player) { + return; + } + _fireEvent(Event.SET_PLAYER, _player, player); + if (_player != null) { + ((TopicImpl)_player).removeRolePlayed(this); + } + _player = player; + if (player != null) { + ((TopicImpl) player).addRolePlayed(this); + } + } + + /* (non-Javadoc) + * @see org.tinytim.TopicMapObjectImpl#remove() + */ + public void remove() throws TMAPIException { + ((AssociationImpl) _parent).removeRole(this); + super.dispose(); + } + +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/AssociationRoleImpl.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/CopyUtils.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/CopyUtils.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/CopyUtils.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,171 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.Iterator; +import java.util.Map; + +import org.tmapi.core.Locator; +import org.tmapi.core.Occurrence; +import org.tmapi.core.Topic; +import org.tmapi.core.TopicMap; +import org.tmapi.core.TopicMapObject; + +/** + * This class provides methods to copy Topic Maps constructs from one + * topic map to another without creating duplicates. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +final class CopyUtils { + + /** + * Copies the topics and associations from the <code>source</code> to the + * <code>target</code> topic map. + * + * @param source The topic map to take the topics and associations from. + * @param target The topic map which should receive the topics and associations. + */ + public static void copy(TopicMap source, TopicMap target) { + _copy((TopicMapImpl) source, (TopicMapImpl) target); + } + + /** + * @see #copy(TopicMap, TopicMap) + */ + @SuppressWarnings("unchecked") + private static void _copy(TopicMapImpl source, TopicMapImpl target) { + if (source == null || target == null) { + throw new IllegalArgumentException("Neither the source topic map nor the target topic map must be null"); + } + if (source == target) { + return; + } + Map<Topic, Topic> mergeMap = target.getCollectionFactory().createMap(); + Topic existing = null; + TopicMapObject existingConstruct = null; + for (Topic topic: source.getTopics()) { + for (Iterator<Locator> iter = topic.getSubjectLocators().iterator(); iter.hasNext();) { + existing = target.getTopicBySubjectLocator(iter.next()); + if (existing != null) { + _addMerge(topic, existing, mergeMap); + } + } + for (Iterator<Locator> iter = topic.getSubjectIdentifiers().iterator(); iter.hasNext();) { + Locator sid = iter.next(); + existing = target.getTopicBySubjectIdentifier(sid); + if (existing != null) { + _addMerge(topic, existing, mergeMap); + } + existingConstruct = target.getObjectByItemIdentifier(sid); + if (existingConstruct instanceof Topic) { + _addMerge(topic, (Topic) existingConstruct, mergeMap); + } + } + for (Iterator<Locator> iter = topic.getSourceLocators().iterator(); iter.hasNext();) { + Locator iid = iter.next(); + existingConstruct = target.getObjectByItemIdentifier(iid); + if (existingConstruct instanceof Topic) { + _addMerge(topic, (Topic) existingConstruct, mergeMap); + } + existing = target.getTopicBySubjectIdentifier(iid); + if (existing != null) { + _addMerge(topic, existing, mergeMap); + } + } + } + if (source.getReifier() != null && target.getReifier() != null) { + _addMerge(source.getReifier(), target.getReifier(), mergeMap); + } + for (Topic topic: source.getTopics()) { + if (!mergeMap.containsKey(topic)) { + _copyTopic(topic, target, mergeMap); + } + } + for (Topic topic: mergeMap.keySet()) { + Topic targetTopic = mergeMap.get(topic); + _copyIdentities(topic, targetTopic); + _copyTypes(topic, targetTopic, mergeMap); + _copyCharacteristics(topic, (TopicImpl)targetTopic, mergeMap); + } + } + + private static Topic _copyTopic(Topic topic, TopicMap target, + Map<Topic, Topic> mergeMap) { + Topic targetTopic = target.createTopic(); + _copyIdentities(topic, targetTopic); + _copyTypes(topic, targetTopic, mergeMap); + _copyCharacteristics(topic, (TopicImpl)targetTopic, mergeMap); + return targetTopic; + } + + @SuppressWarnings("unchecked") + private static void _copyIdentities(Topic topic, Topic targetTopic) { + for(Iterator<Locator> iter = topic.getSubjectIdentifiers().iterator(); iter.hasNext();) { + targetTopic.addSubjectIdentifier(iter.next()); + } + for(Iterator<Locator> iter = topic.getSubjectLocators().iterator(); iter.hasNext();) { + targetTopic.addSubjectLocator(iter.next()); + } + _copyItemIdentifiers((IConstruct)topic, (IConstruct)targetTopic); + } + + @SuppressWarnings("unchecked") + private static void _copyTypes(Topic topic, Topic targetTopic, + Map<Topic, Topic> mergeMap) { + for (Iterator<Topic> iter = topic.getTypes().iterator(); iter.hasNext();) { + Topic type = iter.next(); + Topic targetType = mergeMap.get(type); + if (targetType == null) { + targetType = _copyTopic(type, targetTopic.getTopicMap(), mergeMap); + } + targetTopic.addType(targetType); + } + } + + private static void _copyCharacteristics(Topic topic, TopicImpl targetTopic, + Map<Topic, Topic> mergeMap) { + Map<String, IReifiable> sigs = ((TopicMapImpl) targetTopic.getTopicMap()).getCollectionFactory().<String, IReifiable>createMap(); + for (Occurrence occ: targetTopic.getOccurrences()) { + sigs.put(SignatureGenerator.generateSignature(occ), (IReifiable)occ); + } + } + + private static void _copyItemIdentifiers(IConstruct source, IConstruct target) { + for(Locator iid: source.getItemIdentifiers()) { + target.addSourceLocator(iid); + } + } + + private static void _addMerge(Topic source, Topic target, Map<Topic, Topic> mergeMap) { + Topic prevTarget = mergeMap.get(source); + if (prevTarget != null) { + if (!prevTarget.equals(target)) { + MergeUtils.merge(target, prevTarget); + } + } + else { + mergeMap.put(source, target); + } + } + +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/CopyUtils.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/DatatypeAwareConstruct.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/DatatypeAwareConstruct.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/DatatypeAwareConstruct.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,117 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.Collection; + +import org.tmapi.core.Locator; +import org.tmapi.core.Topic; + +/** + * Implementation of {@link org.tinytim.IDatatypeAwareConstruct}. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +abstract class DatatypeAwareConstruct extends Typed implements + IDatatypeAwareConstruct, IScoped { + + private String _value; + private Locator _resource; + + DatatypeAwareConstruct(TopicMapImpl topicMap, Topic type, String value, Collection<Topic> scope) { + super(topicMap, type, scope); + _value = value; + } + + DatatypeAwareConstruct(TopicMapImpl topicMap, Topic type, Locator value, Collection<Topic> scope) { + super(topicMap, type, scope); + _resource = value; + } + + /* (non-Javadoc) + * @see org.tinytim.IDatatypeAwareConstruct#getValue2() + */ + public String getValue2() { + if (_value != null) { + return _value; + } + return _resource != null ? _resource.getReference() : ""; + } + + /** + * + * + * @param value + */ + public void setValue(String value) { + _fireEvent(Event.SET_VALUE, _value, value); + _resource = null; + _value = value; + } + + /** + * + * + * @return + */ + public String getValue() { + return _value; + } + + /** + * + * + * @return + */ + public Locator getResource() { + return _resource; + } + + /* (non-Javadoc) + * @see org.tmapi.core.Occurrence#setResource(org.tmapi.core.Locator) + */ + public void setResource(Locator value) { + _fireEvent(Event.SET_VALUE, _value, value); + _value = null; + _resource = value; + } + + /* (non-Javadoc) + * @see org.tinytim.IDatatypeAwareConstruct#getDatatype() + */ + public Locator getDatatype() { + if (_value != null || _resource == null) { + return STRING; + } + return ANY_URI; + } + + /* (non-Javadoc) + * @see org.tinytim.Construct#dispose() + */ + @Override + protected void dispose() { + _value = null; + _resource = null; + super.dispose(); + } +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/DatatypeAwareConstruct.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/IDatatypeAwareConstruct.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/IDatatypeAwareConstruct.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/IDatatypeAwareConstruct.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,56 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import org.tmapi.core.Locator; + +/** + * Indicates that a Topic Maps construct has a value and a datatype. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +interface IDatatypeAwareConstruct extends IConstruct { + + static final String _XSD_BASE = "http://www.w3.org/2001/XMLSchema#"; + static final Locator STRING = new IRI(_XSD_BASE + "string"); + static final Locator ANY_URI = new IRI(_XSD_BASE + "anyURI"); + + /** + * The value of this Topic Maps construct. + * + * This method differs from TMAPI: This method MUST return the value OR the + * locator as string. This method should be removed if we have TMAPI 2.0 + * (maybe the whole interface should be removed). + * Currently, the {@link SignatureGenerator} needs it. + * + * @return The value. + */ + public String getValue2(); + + /** + * Returns the datatype of this Topic Maps construct. + * + * @return The datatype. + */ + public Locator getDatatype(); + +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/IDatatypeAwareConstruct.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/IdentityManager.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/IdentityManager.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/IdentityManager.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,250 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.Map; + +import org.tmapi.core.DuplicateSourceLocatorException; +import org.tmapi.core.Locator; +import org.tmapi.core.ModelConstraintException; +import org.tmapi.core.Topic; +import org.tmapi.core.TopicsMustMergeException; + +/** + * The identity manager takes care about the TMDM identity constraints and + * provides an index to get Topic Maps constructs by their identity. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +final class IdentityManager { + + private long _nextId; + private Map<Locator, Topic> _sid2Topic; + private Map<Locator, Topic> _slo2Topic; + private Map<Locator, IConstruct> _iid2Construct; + private Map<String, IConstruct> _id2Construct; + + IdentityManager(TopicMapImpl tm) { + ICollectionFactory collFactory = tm.getCollectionFactory(); + _id2Construct = collFactory.<String, IConstruct>createMap(); + _sid2Topic = collFactory.<Locator, Topic>createMap(); + _slo2Topic = collFactory.<Locator, Topic>createMap(); + _iid2Construct = collFactory.<Locator, IConstruct>createMap(); + _subscribe(tm); + _register(tm); + } + + private void _subscribe(IEventPublisher publisher) { + IEventHandler handler = new TopicMapsConstructAddHandler(); + publisher.subscribe(Event.ADD_TOPIC, handler); + publisher.subscribe(Event.ADD_ASSOCIATION, handler); + publisher.subscribe(Event.ADD_ROLE, handler); + publisher.subscribe(Event.ADD_OCCURRENCE, handler); + publisher.subscribe(Event.ADD_NAME, handler); + publisher.subscribe(Event.ADD_VARIANT, handler); + handler = new TopicMapsConstructRemoveHandler(); + publisher.subscribe(Event.REMOVE_TOPIC, handler); + publisher.subscribe(Event.REMOVE_ASSOCIATION, handler); + publisher.subscribe(Event.REMOVE_ROLE, handler); + publisher.subscribe(Event.REMOVE_OCCURRENCE, handler); + publisher.subscribe(Event.REMOVE_NAME, handler); + publisher.subscribe(Event.REMOVE_VARIANT, handler); + handler = new AddItemIdentifierHandler(); + publisher.subscribe(Event.ADD_IID, handler); + handler = new RemoveItemIdentifierHandler(); + publisher.subscribe(Event.REMOVE_IID, handler); + handler = new AddSubjectIdentifierHandler(); + publisher.subscribe(Event.ADD_SID, handler); + handler = new RemoveSubjectIdentifierHandler(); + publisher.subscribe(Event.REMOVE_SID, handler); + handler = new AddSubjectLocatorHandler(); + publisher.subscribe(Event.ADD_SLO, handler); + handler = new RemoveSubjectLocatorHandler(); + publisher.subscribe(Event.REMOVE_SLO, handler); + handler = new ReifierConstraintHandler(); + publisher.subscribe(Event.SET_REIFIER, handler); + } + + private void _register(IConstruct construct) { + Construct c = (Construct) construct; + if (c._id == null) { + c._id = "" + _nextId++; + } + if (!_id2Construct.containsKey(c)) { + _id2Construct.put(c._id, c); + } + } + + private void _unregister(IConstruct construct) { + _id2Construct.remove(((Construct) construct)._id); + } + + public IConstruct getConstructById(String id) { + return _id2Construct.get(id); + } + + public Topic getTopicBySubjectIdentifier(Locator sid) { + return _sid2Topic.get(sid); + } + + public Topic getTopicBySubjectLocator(Locator slo) { + return _slo2Topic.get(slo); + } + + public IConstruct getConstructByItemIdentifier(Locator iid) { + return _iid2Construct.get(iid); + } + + public void close() { + _id2Construct = null; + _iid2Construct = null; + _sid2Topic = null; + _slo2Topic = null; + } + + private class TopicMapsConstructAddHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + _register((IConstruct)newValue); + } + } + + private class TopicMapsConstructRemoveHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + _unregister((IConstruct)oldValue); + } + } + + /** + * Checks identity constraints and adds the Topic Maps construct and the + * item identifier to the index. + */ + private class AddItemIdentifierHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + Locator iid = (Locator) newValue; + IConstruct existing = _iid2Construct.get(iid); + if (existing != null) { + if (existing != sender) { + if (sender instanceof Topic && existing instanceof Topic) { + throw new TopicsMustMergeException((Topic) sender, (Topic) existing, "A topic with the same item identifier '" + iid.getReference() + "' exists"); + } + throw new DuplicateSourceLocatorException(sender, existing, iid, "A Topic Maps construct with the same item identifier '" + iid.getReference() + "' exists"); + } + } + if (sender instanceof Topic) { + Topic existingTopic = _sid2Topic.get(iid); + if (existingTopic != null && existingTopic != sender) { + throw new TopicsMustMergeException((Topic) sender, existingTopic, "A topic with a subject identifier equals to the item identifier '" + iid.getReference() + "' exists"); + } + } + _iid2Construct.put(iid, sender); + } + } + + /** + * Removes an item identifier and its Topic Maps constructs from the index. + */ + private class RemoveItemIdentifierHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + _iid2Construct.remove(oldValue); + } + } + + /** + * Checks identity constraints and adds the topic and the + * subject identifier to the index. + */ + private class AddSubjectIdentifierHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + Topic topic = (Topic) sender; + Locator sid = (Locator) newValue; + IConstruct existing = (IConstruct) _sid2Topic.get(sid); + if (existing != null && existing != topic) { + throw new TopicsMustMergeException(topic, (Topic) existing, "A topic with the same subject identifier '" + sid.getReference() + "' exists"); + } + existing = _iid2Construct.get(sid); + if (existing != null && existing instanceof Topic && existing != topic) { + throw new TopicsMustMergeException(topic, (Topic) existing, "A topic with an item identifier equals to the subject identifier '" + sid.getReference() + "' exists"); + } + _sid2Topic.put(sid, topic); + } + } + + /** + * Removes a subject identifier and its topic from the index. + */ + private class RemoveSubjectIdentifierHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + Locator slo = (Locator) oldValue; + _sid2Topic.remove(slo); + } + } + + /** + * Checks identity constraints and adds the topic and the + * subject locator to the index. + */ + private class AddSubjectLocatorHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + Topic topic = (Topic) sender; + Locator slo = (Locator) newValue; + Topic existing = _slo2Topic.get(slo); + if (existing != null && existing != topic) { + throw new TopicsMustMergeException(topic, existing, "A topic with the same subject locator '" + slo.getReference() + "' exists"); + } + _slo2Topic.put(slo, topic); + } + } + + /** + * Removes a subject locator and its topic from the index. + */ + private class RemoveSubjectLocatorHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + Locator slo = (Locator) oldValue; + _slo2Topic.remove(slo); + } + } + + /** + * Checks if setting the reifier is allowed. + */ + private static class ReifierConstraintHandler implements IEventHandler { + public void handleEvent(Event evt, IConstruct sender, Object oldValue, + Object newValue) { + if (newValue == null) { + return; + } + IReifiable currentReified = ((TopicImpl) newValue)._reified; + if (currentReified != null && currentReified != sender) { + throw new ModelConstraintException(sender, "The topic reifies another Topic Maps construct"); + } + } + } +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/IdentityManager.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/MergeUtils.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/MergeUtils.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/MergeUtils.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,339 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.tinytim.index.IScopedIndex; +import org.tinytim.index.ITypeInstanceIndex; +import org.tinytim.index.IndexManager; +import org.tmapi.core.Association; +import org.tmapi.core.AssociationRole; +import org.tmapi.core.Locator; +import org.tmapi.core.ModelConstraintException; +import org.tmapi.core.Occurrence; +import org.tmapi.core.TMAPIException; +import org.tmapi.core.TMAPIRuntimeException; +import org.tmapi.core.Topic; +import org.tmapi.core.TopicMap; +import org.tmapi.core.TopicName; +import org.tmapi.core.Variant; + +/** + * This class does provides functions to merge topic maps and topics. + * + * This class relies on the implementation of tinyTiM, if the implementation + * changes, check the <code>==</code> comparisons. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +final class MergeUtils { + + private MergeUtils() { + // noop. + } + + /** + * Merges two topic maps. + * + * @param source The source topic map. + * @param target The target topic map which receives all + * topics / associations from <code>source</code>. + */ + public static void merge(TopicMap source, TopicMap target) { + CopyUtils.copy(source, target); + } + + /** + * Merges two topics. + * + * The topics MUST belong to the same topic map. The <code>source</code> + * will be removed from the topic map and <code>target</code> takes all + * characteristics of the <code>source</code>. + * + * @param source The source topic. + * @param target The target topic which receives all characteristics from + * <code>source</code>. + */ + public static void merge(Topic source, Topic target) { + _merge((TopicImpl) source, (TopicImpl) target); + } + + /** + * @see #merge(Topic, Topic) + */ + private static void _merge(TopicImpl source, TopicImpl target) { + if (source == null || target == null) { + throw new IllegalArgumentException("Neither the source topic nor the target topic must be null"); + } + if (source == target) { + return; + } + if (source.getTopicMap() != target.getTopicMap()) { + throw new IllegalArgumentException("The topics must belong to the same topic map"); + } + IReifiable sourceReifiable = source._reified; + if (sourceReifiable != null && target._reified != null) { + // This should be enforced by the model + assert sourceReifiable != target._reified; + throw new ModelConstraintException(target, "The topics cannot be merged. They reify different Topic Maps constructs"); + } + _moveItemIdentifiers((IConstruct)source, (IConstruct)target); + if (sourceReifiable != null) { + sourceReifiable.setReifier(target); + } + List<Locator> locs = new ArrayList<Locator>(source.getSubjectIdentifiers()); + for (Locator sid: locs) { + source.removeSubjectIdentifier(sid); + target.addSubjectIdentifier(sid); + } + locs = new ArrayList<Locator>(source.getSubjectLocators()); + for (Locator slo: locs) { + source.removeSubjectLocator(slo); + target.addSubjectLocator(slo); + } + _replaceTopics(source, target); + for(Topic type: source.getTypes()) { + target.addType(type); + } + Map<String, IReifiable> sigs = ((TopicMapImpl) source.getTopicMap()).getCollectionFactory().<String, IReifiable>createMap(); + for (Occurrence occ: target.getOccurrences()) { + sigs.put(SignatureGenerator.generateSignature(occ), (IReifiable)occ); + } + IReifiable existing = null; + for (Occurrence occ: new ArrayList<Occurrence>(source.getOccurrences())) { + existing = sigs.get(SignatureGenerator.generateSignature(occ)); + if (existing != null) { + handleExistingConstruct((IReifiable) occ, existing); + removeConstruct((IConstruct)occ); + } + else { + source.removeOccurrence(occ); + target.addOccurrence(occ); + } + } + sigs.clear(); + for (TopicName name: target.getTopicNames()) { + sigs.put(SignatureGenerator.generateSignature(name), (IReifiable) name); + } + for (TopicName name: new ArrayList<TopicName>(source.getTopicNames())) { + existing = sigs.get(SignatureGenerator.generateSignature(name)); + if (existing != null) { + handleExistingConstruct((IReifiable) name, existing); + moveVariants((TopicNameImpl)name, (TopicNameImpl) existing); + removeConstruct((IConstruct) name); + } + else { + source.removeName(name); + target.addName(name); + } + } + sigs.clear(); + for (AssociationRole role: target.getRolesPlayed()) { + Association parent = role.getAssociation(); + sigs.put(SignatureGenerator.generateSignature(parent), (IReifiable) parent); + } + for (AssociationRole role: new ArrayList<AssociationRole>(source.getRolesPlayed())) { + role.setPlayer(target); + Association parent = role.getAssociation(); + existing = sigs.get(SignatureGenerator.generateSignature(parent)); + if (existing != null) { + handleExistingConstruct((IReifiable)parent, existing); + _moveRoleCharacteristics(parent, (Association)existing); + removeConstruct((IConstruct)parent); + } + } + removeConstruct(source); + } + + /** + * Removes a Topic Maps construct. + * + * If the construct is not removable, a runtime exception is thrown. + * + * @param construct The construct to remove. + */ + static void removeConstruct(IConstruct construct) { + try { + construct.remove(); + } + catch (TMAPIException ex) { + throw new TMAPIRuntimeException("Unexpected exception while Topic Maps construct removal", ex); + } + } + + /** + * Moves role item identifiers and reifier from the <code>source</code> to + * the <code>target</code>'s equivalent role. + * + * @param source The association to remove the characteristics from. + * @param target The association which takes the role characteristics. + */ + @SuppressWarnings("unchecked") + private static void _moveRoleCharacteristics(Association source, Association target) { + Map<String, AssociationRole> sigs = ((TopicMapImpl) target.getTopicMap()).getCollectionFactory().<String, AssociationRole>createMap(); + for (AssociationRole role: ((AssociationImpl)target).getAssociationRoles()) { + sigs.put(SignatureGenerator.generateSignature(role), role); + } + List<AssociationRole> roles = new ArrayList<AssociationRole>(source.getAssociationRoles()); + for (AssociationRole role: roles) { + handleExistingConstruct((IReifiable)role, (IReifiable)sigs.get(SignatureGenerator.generateSignature(role))); + removeConstruct((IConstruct)role); + } + } + + /** + * Moves the variants from <code>source</code> to <code>target</code>. + * + * @param source The name to take the variants from. + * @param target The target to add the variants to. + */ + static void moveVariants(TopicNameImpl source, TopicNameImpl target) { + Map<String, Variant> sigs = ((TopicMapImpl) target.getTopicMap()).getCollectionFactory().<String, Variant>createMap(); + for (Variant var: target.getVariants()) { + sigs.put(SignatureGenerator.generateSignature(var), var); + } + Variant existing = null; + for (Variant var: new ArrayList<Variant>(source.getVariants())) { + existing = sigs.get(SignatureGenerator.generateSignature(var)); + if (existing != null) { + handleExistingConstruct((IReifiable) var, (IReifiable) existing); + removeConstruct((IConstruct)var); + } + else { + source.removeVariant(var); + target.addVariant(var); + } + } + } + + /** + * Moves the item identifiers and reifier from <code>source</code> to + * <code>target</code>. + * + * If the <code>source</code> is reified, the <code>target</code>'s reifier + * is set to the source reifier unless the target is also reified. + * If <code>source</code> and <code>target</code> are reified, the reifiers + * are merged. + * + * @param source The source Topic Maps construct. + * @param target The target Topic Maps construct. + */ + static void handleExistingConstruct(IReifiable source, IReifiable target) { + _moveItemIdentifiers(source, target); + if (source.getReifier() == null) { + return; + } + if (target.getReifier() != null) { + Topic reifier = source.getReifier(); + source.setReifier(null); + merge(reifier, target.getReifier()); + } + else { + Topic reifier = source.getReifier(); + source.setReifier(null); + target.setReifier(reifier); + } + } + + /** + * Replaces the <code>source</code> topic with the <code>replacement</code> + * everywhere where <code>source</code> is used as type or theme. + * + * @param source The topic to replace. + * @param replacement The topic which replaces the <code>source</code>. + */ + private static void _replaceTopics(Topic source, Topic replacement) { + TopicMapImpl tm = (TopicMapImpl) replacement.getTopicMap(); + IndexManager idxMan = tm.getIndexManager(); + ITypeInstanceIndex typeInstanceIndex = idxMan.getTypeInstanceIndex(); + if (!typeInstanceIndex.isAutoUpdated()) { + typeInstanceIndex.reindex(); + } + List<Topic> topics = new ArrayList<Topic>(typeInstanceIndex.getTopics(source)); + for (Topic topic: topics) { + topic.removeType(source); + topic.addType(replacement); + } + Collection<ITyped> typed = new ArrayList<ITyped>(typeInstanceIndex.getAssociations(source)); + _replaceTopicAsType(typed, replacement); + typed = new ArrayList<ITyped>(typeInstanceIndex.getRoles(source)); + _replaceTopicAsType(typed, replacement); + typed = new ArrayList<ITyped>(typeInstanceIndex.getOccurrences(source)); + _replaceTopicAsType(typed, replacement); + typed = new ArrayList<ITyped>(typeInstanceIndex.getNames(source)); + _replaceTopicAsType(typed, replacement); + typeInstanceIndex.close(); + IScopedIndex scopedIndex = idxMan.getScopedIndex(); + if (!scopedIndex.isAutoUpdated()) { + scopedIndex.reindex(); + } + Collection<IScoped> scoped = new ArrayList<IScoped>(scopedIndex.getAssociationsByTheme(source)); + _replaceTopicAsTheme(scoped, source, replacement); + scoped = new ArrayList<IScoped>(scopedIndex.getOccurrencesByTheme(source)); + _replaceTopicAsTheme(scoped, source, replacement); + scoped = new ArrayList<IScoped>(scopedIndex.getNamesByTheme(source)); + _replaceTopicAsTheme(scoped, source, replacement); + scoped = new ArrayList<IScoped>(scopedIndex.getVariantsByTheme(source)); + _replaceTopicAsTheme(scoped, source, replacement); + scopedIndex.close(); + } + + /** + * Sets <code>replacement</code> as type of each typed Topic Maps construct. + * + * @param typedConstructs A collection of typed constructs. + * @param replacement The type. + */ + private static void _replaceTopicAsType(Collection<ITyped> typedConstructs, + Topic replacement) { + for (ITyped typed: typedConstructs) { + typed.setType(replacement); + } + } + + private static void _replaceTopicAsTheme(Collection<IScoped> scopedCollection, + Topic oldTheme, Topic newTheme) { + for (IScoped scoped: scopedCollection) { + scoped.removeTheme(oldTheme); + scoped.addTheme(newTheme); + } + } + + /** + * Moves the item identifiers from <code>source</code> to <code>target</code>. + * + * @param source The source to remove the item identifiers from. + * @param target The target which get the item identifiers. + */ + private static void _moveItemIdentifiers(IConstruct source, IConstruct target) { + List<Locator> iids = new ArrayList<Locator>(source.getItemIdentifiers()); + for (Locator iid: iids) { + source.removeItemIdentifier(iid); + target.addItemIdentifier(iid); + } + } + +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/MergeUtils.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/OccurrenceImpl.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/OccurrenceImpl.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/OccurrenceImpl.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,62 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.Collection; + +import org.tmapi.core.Locator; +import org.tmapi.core.Occurrence; +import org.tmapi.core.TMAPIException; +import org.tmapi.core.Topic; + +/** + * {@link org.tmapi.core.Occurrence} implementation. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +public final class OccurrenceImpl extends DatatypeAwareConstruct implements + Occurrence, ITyped { + + OccurrenceImpl(TopicMapImpl topicMap, Topic type, String value, Collection<Topic> scope) { + super(topicMap, type, value, scope); + } + + OccurrenceImpl(TopicMapImpl topicMap, Topic type, Locator value, Collection<Topic> scope) { + super(topicMap, type, value, scope); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Occurrence#getTopic() + */ + public Topic getTopic() { + return (Topic) _parent; + } + + /* (non-Javadoc) + * @see org.tmapi.core.TopicMapObject#remove() + */ + public void remove() throws TMAPIException { + ((TopicImpl) _parent).removeOccurrence(this); + super.dispose(); + } + +} Property changes on: tinytim/trunk/src/main/java/org/tinytim/OccurrenceImpl.java ___________________________________________________________________ Name: svn:keywords + Rev Date Id Name: svn:eol-style + native Added: tinytim/trunk/src/main/java/org/tinytim/TopicImpl.java =================================================================== --- tinytim/trunk/src/main/java/org/tinytim/TopicImpl.java (rev 0) +++ tinytim/trunk/src/main/java/org/tinytim/TopicImpl.java 2008-04-21 14:59:01 UTC (rev 26) @@ -0,0 +1,317 @@ +/* + * This is tinyTiM, a tiny Topic Maps engine. + * + * Copyright (C) 2008 Lars Heuer (heuer[at]semagia.com) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +package org.tinytim; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +import org.tmapi.core.AssociationRole; +import org.tmapi.core.Locator; +import org.tmapi.core.MergeException; +import org.tmapi.core.ModelConstraintException; +import org.tmapi.core.Occurrence; +import org.tmapi.core.Topic; +import org.tmapi.core.TopicInUseException; +import org.tmapi.core.TopicMapObject; +import org.tmapi.core.TopicName; + +/** + * {@link org.tmapi.core.Topic} implementation. + * + * @author Lars Heuer (heuer[at]semagia.com) <a href="http://www.semagia.com/">Semagia</a> + * @version $Rev:$ - $Date:$ + */ +public final class TopicImpl extends Construct implements Topic { + + private Set<AssociationRole> _rolesPlayed; + IReifiable _reified; + private Set<Topic> _types; + private Set<Locator> _sids; + private Set<Locator> _slos; + private Set<Occurrence> _occs; + private Set<TopicName> _names; + + TopicImpl(TopicMapImpl topicMap) { + super(topicMap); + ICollectionFactory collFactory = topicMap.getCollectionFactory(); + _sids = collFactory.<Locator>createSet(2); + _occs = collFactory.<Occurrence>createSet(2); + _names = collFactory.<TopicName>createSet(2); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getSubjectIdentifiers() + */ + public Set<Locator> getSubjectIdentifiers() { + return Collections.unmodifiableSet(_sids); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#addSubjectIdentifier(org.tmapi.core.Locator) + */ + public void addSubjectIdentifier(Locator sid) throws MergeException { + if (_sids.contains(sid)) { + return; + } + _fireEvent(Event.ADD_SID, null, sid); + _sids.add(sid); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#removeSubjectIdentifier(org.tmapi.core.Locator) + */ + public void removeSubjectIdentifier(Locator sid) { + if (!_sids.contains(sid)) { + return; + } + _fireEvent(Event.REMOVE_SID, sid, null); + _sids.remove(sid); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getSubjectLocators() + */ + public Set<Locator> getSubjectLocators() { + return _slos == null ? Collections.<Locator>emptySet() + : Collections.unmodifiableSet(_slos); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#addSubjectLocator(org.tmapi.core.Locator) + */ + public void addSubjectLocator(Locator slo) throws MergeException, + ModelConstraintException { + if (_slos != null && _sids.contains(slo)) { + return; + } + _fireEvent(Event.ADD_SLO, null, slo); + if (_slos == null) { + _slos = _tm.getCollectionFactory().createSet(); + } + _slos.add(slo); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#removeSubjectLocator(org.tmapi.core.Locator) + */ + public void removeSubjectLocator(Locator slo) { + if (_slos == null || !_slos.contains(slo)) { + return; + } + _fireEvent(Event.REMOVE_SLO, slo, null); + _sids.remove(slo); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getOccurrences() + */ + public Set<Occurrence> getOccurrences() { + return Collections.unmodifiableSet(_occs); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#createOccurrence(java.lang.String, org.tmapi.core.Topic, java.util.Collection) + */ + @SuppressWarnings("unchecked") + public Occurrence createOccurrence(String value, Topic type, Collection scope) { + Occurrence occ = new OccurrenceImpl(_tm, type, value, scope); + addOccurrence(occ); + return occ; + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#createOccurrence(org.tmapi.core.Locator, org.tmapi.core.Topic, java.util.Collection) + */ + @SuppressWarnings("unchecked") + public Occurrence createOccurrence(Locator value, Topic type, Collection scope) { + Occurrence occ = new OccurrenceImpl(_tm, type, value, scope); + addOccurrence(occ); + return occ; + } + + /** + * Adds an occurrence to the [occurrences] property. + * + * @param occ The occurrence to add. + */ + void addOccurrence(Occurrence occ) { + OccurrenceImpl o = (OccurrenceImpl) occ; + if (o._parent == this) { + return; + } + _fireEvent(Event.ADD_OCCURRENCE, null, o); + o._parent = this; + _occs.add(o); + } + + /** + * Removes an occurrence from the [occurrences] property. + * + * @param occ The occurrence to remove. + */ + void removeOccurrence(Occurrence occ) { + OccurrenceImpl o = (OccurrenceImpl) occ; + if (o._parent != this) { + return; + } + _fireEvent(Event.REMOVE_OCCURRENCE, o, null); + _occs.remove(o); + o._parent = null; + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getTopicNames() + */ + public Set<TopicName> getTopicNames() { + return Collections.unmodifiableSet(_names); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#createTopicName(java.lang.String, java.util.Collection) + */ + @SuppressWarnings("unchecked") + public TopicName createTopicName(String value, Collection scope) + throws MergeException { + return createTopicName(value, null, scope); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#createTopicName(java.lang.String, org.tmapi.core.Topic, java.util.Collection) + */ + @SuppressWarnings("unchecked") + public TopicName createTopicName(String value, Topic type, Collection scope) + throws UnsupportedOperationException, MergeException { + TopicNameImpl name = new TopicNameImpl(_tm, type, value, scope); + addName(name); + return name; + } + + void addName(TopicName name) { + TopicNameImpl n = (TopicNameImpl) name; + if (n._parent == this) { + return; + } + assert n._parent == null; + _fireEvent(Event.ADD_NAME, null, n); + n._parent = this; + _names.add(n); + } + + void removeName(TopicName name) { + TopicNameImpl n = (TopicNameImpl) name; + if (n._parent != this) { + return; + } + _fireEvent(Event.REMOVE_NAME, n, null); + _names.remove(n); + n._parent = null; + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getReified() + */ + public Set<TopicMapObject> getReified() { + return _reified != null ? Collections.<TopicMapObject>singleton(_reified) + : Collections.<TopicMapObject>emptySet(); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getRolesPlayed() + */ + public Set<AssociationRole> getRolesPlayed() { + return _rolesPlayed == null ? Collections.<AssociationRole>emptySet() + : Collections.unmodifiableSet(_rolesPlayed); + } + + void addRolePlayed(AssociationRole role) { + if (_rolesPlayed == null) { + _rolesPlayed = _tm.getCollectionFactory().createSet(4); + } + _rolesPlayed.add(role); + } + + void removeRolePlayed(AssociationRole role) { + if (_rolesPlayed == null) { + return; + } + _rolesPlayed.remove(role); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#getTypes() + */ + public Set<Topic> getTypes() { + return _types == null ? Collections.<Topic>emptySet() + : Collections.unmodifiableSet(_types); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#addType(org.tmapi.core.Topic) + */ + public void addType(Topic type) { + if (_types != null && _types.contains(type)) { + return; + } + _fireEvent(Event.ADD_TYPE, null, type); + if (_types == null) { + _types = _tm.getCollectionFactory().createSet(); + } + _types.add(type); + } + + /* (non-Javadoc) + * @see org.tmapi.core.Topic#removeType(org.tmapi.core.Topic) + */ + public void removeType(Topic type) { + if (_types ==... [truncated message content] |