/* * #! * 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.rdbms; import java.util.Collection; import java.util.Collections; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.persistence.proxy.IdentityIF; import net.ontopia.persistence.proxy.TransactionIF; import net.ontopia.topicmaps.core.AssociationIF; import net.ontopia.topicmaps.core.AssociationRoleIF; import net.ontopia.topicmaps.core.TopicNameIF; import net.ontopia.topicmaps.core.ConstraintViolationException; import net.ontopia.topicmaps.core.CrossTopicMapException; import net.ontopia.topicmaps.core.OccurrenceIF; import net.ontopia.topicmaps.core.ReifiableIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.impl.utils.ObjectStrings; import net.ontopia.utils.ObjectUtils; import net.ontopia.utils.CompactHashSet; /** * INTERNAL: The rdbms topic implementation. */ public class Topic extends TMObject implements TopicIF { // --------------------------------------------------------------------------- // Persistent property declarations // --------------------------------------------------------------------------- protected static final int LF_subjects = 2; protected static final int LF_indicators = 3; protected static final int LF_types = 4; protected static final int LF_names = 5; protected static final int LF_occurrences = 6; protected static final int LF_roles = 7; // Query field? protected static final int LF_reified = 8; protected static final String[] fields = {"sources", "topicmap", "subjects", "indicators", "types", "names", "occurs", "roles", "reified"}; public void detach() { detachCollectionField(LF_sources); detachField(LF_topicmap); detachField(LF_reified); detachCollectionField(LF_subjects); detachCollectionField(LF_indicators); detachCollectionField(LF_types); detachCollectionField(LF_names); detachCollectionField(LF_occurrences); detachCollectionField(LF_roles); } // --------------------------------------------------------------------------- // Data members // --------------------------------------------------------------------------- public static final String CLASS_INDICATOR = "T"; public Topic() { } public Topic(TransactionIF txn) { super(txn); } // --------------------------------------------------------------------------- // PersistentIF implementation // --------------------------------------------------------------------------- public int _p_getFieldCount() { return fields.length; } // --------------------------------------------------------------------------- // TMObjectIF implementation // --------------------------------------------------------------------------- public String getClassIndicator() { return CLASS_INDICATOR; } public String getObjectId() { return (id == null ? null : CLASS_INDICATOR + id.getKey(0)); } /** * INTERNAL: Sets the topic map that the object belongs to. [parent] */ void setTopicMap(TopicMap topicmap) { // Notify transaction transactionChanged(topicmap); valueChanged(LF_topicmap, topicmap, true); // Inform topic names for (TopicName topicname : this.<TopicName>loadCollectionField(LF_names)) { topicname.setTopicMap(topicmap); } // Inform occurrences for (Occurrence occurrence : this.<Occurrence>loadCollectionField(LF_occurrences)) { occurrence.setTopicMap(topicmap); } } // --------------------------------------------------------------------------- // TopicIF implementation // --------------------------------------------------------------------------- public Collection<LocatorIF> getSubjectLocators() { return this.<LocatorIF>loadCollectionField(LF_subjects); } public void addSubjectLocator(LocatorIF subject_locator) throws ConstraintViolationException { if (subject_locator == null) throw new NullPointerException("null is not a valid argument."); // Notify topic map TopicMap tm = (TopicMap)getTopicMap(); if (tm == null) throw new ConstraintViolationException("Cannot modify subject locator when topic isn't attached to a topic map."); // Check to see if subject is already a subject locator of this topic. Collection<LocatorIF> subjects = this.<LocatorIF>loadCollectionField(LF_subjects); if (subjects.contains(subject_locator)) return; if (!(subject_locator instanceof SubjectLocator)) subject_locator = new SubjectLocator(subject_locator); // Notify listeners fireEvent(TopicIF.EVENT_ADD_SUBJECTLOCATOR, subject_locator, null); // Notify transaction valueAdded(LF_subjects, subject_locator, true); } public void removeSubjectLocator(LocatorIF subject_locator) { if (subject_locator == null) throw new NullPointerException("null is not a valid argument."); // Notify topic map TopicMap tm = (TopicMap)getTopicMap(); if (tm == null) throw new ConstraintViolationException("Cannot modify subject locator when topic isn't attached to a topic map."); // Check to see if subject locator is a subject locator of this topic. Collection<LocatorIF> subjects = this.<LocatorIF>loadCollectionField(LF_subjects); if (!subjects.contains(subject_locator)) return; if (!(subject_locator instanceof SubjectLocator)) subject_locator = new SubjectLocator(subject_locator); // Notify listeners fireEvent(TopicIF.EVENT_REMOVE_SUBJECTLOCATOR, null, subject_locator); // Notify transaction valueRemoved(LF_subjects, subject_locator, true); } public Collection<LocatorIF> getSubjectIdentifiers() { return this.<LocatorIF>loadCollectionField(LF_indicators); } public void addSubjectIdentifier(LocatorIF subject_indicator) throws ConstraintViolationException { if (subject_indicator == null) throw new NullPointerException("null is not a valid argument."); // Notify topic map TopicMap tm = (TopicMap)getTopicMap(); if (tm == null) throw new ConstraintViolationException("Cannot modify subject indicator when topic isn't attached to a topic map."); // Check to see if subject is already a subject indicator of this topic. Collection<LocatorIF> indicators = this.<LocatorIF>loadCollectionField(LF_indicators); if (indicators.contains(subject_indicator)) return; if (!(subject_indicator instanceof SubjectIndicatorLocator)) subject_indicator = new SubjectIndicatorLocator(subject_indicator); // Notify listeners fireEvent(TopicIF.EVENT_ADD_SUBJECTIDENTIFIER, subject_indicator, null); // Notify transaction valueAdded(LF_indicators, subject_indicator, true); } public void removeSubjectIdentifier(LocatorIF subject_indicator) { if (subject_indicator == null) throw new NullPointerException("null is not a valid argument."); // Notify topic map TopicMap tm = (TopicMap)getTopicMap(); if (tm == null) throw new ConstraintViolationException("Cannot modify subject indicator when topic isn't attached to a topic map."); // Check to see if subject indicator is a subject indicator of this topic. Collection<LocatorIF> indicators = this.<LocatorIF>loadCollectionField(LF_indicators); if (!indicators.contains(subject_indicator)) return; if (!(subject_indicator instanceof SubjectIndicatorLocator)) subject_indicator = new SubjectIndicatorLocator(subject_indicator); // Notify listeners fireEvent(TopicIF.EVENT_REMOVE_SUBJECTIDENTIFIER, null, subject_indicator); // Notify transaction valueRemoved(LF_indicators, subject_indicator, true); } public Collection<TopicNameIF> getTopicNames() { return this.<TopicNameIF>loadCollectionField(LF_names); } public Collection<TopicNameIF> getTopicNamesByType(TopicIF type) { return ((TopicMap)getTopicMap()).getTopicNamesByType(this, type); } void addTopicName(TopicNameIF name) { if (name == null) throw new NullPointerException("null is not a valid argument."); // Check to see if name is already a member of this topic if (name.getTopic() == this) return; // Check if used elsewhere. if (name.getTopic() != null) throw new ConstraintViolationException("Moving objects is not allowed."); // Notify listeners fireEvent(TopicIF.EVENT_ADD_TOPICNAME, name, null); // Set topic property ((TopicName)name).setTopic(this); // Notify transaction valueAdded(LF_names, name, false); } void removeTopicName(TopicNameIF name) { if (name == null) throw new NullPointerException("null is not a valid argument."); // Check to see if name is not a member of this topic if (name.getTopic() != this) return; // Notify listeners fireEvent(TopicIF.EVENT_REMOVE_TOPICNAME, null, name); // Unset topic property ((TopicName)name).setTopic(null); // Notify transaction valueRemoved(LF_names, name, false); } public Collection<OccurrenceIF> getOccurrences() { return this.<OccurrenceIF>loadCollectionField(LF_occurrences); } public Collection<OccurrenceIF> getOccurrencesByType(TopicIF type) { return ((TopicMap)getTopicMap()).getOccurrencesByType(this, type); } void addOccurrence(OccurrenceIF occurrence) { if (occurrence == null) throw new NullPointerException("null is not a valid argument."); // Check to see if occurrence is already a member of this topic if (occurrence.getTopic() == this) return; // Check if used elsewhere. if (occurrence.getTopic() != null) throw new ConstraintViolationException("Moving objects is not allowed."); // Notify listeners fireEvent(TopicIF.EVENT_ADD_OCCURRENCE, occurrence, null); // Set topic property ((Occurrence)occurrence).setTopic(this); // Notify transaction valueAdded(LF_occurrences, occurrence, false); } void removeOccurrence(OccurrenceIF occurrence) { if (occurrence == null) throw new NullPointerException("null is not a valid argument."); // Check to see if occurrence is not a member of this topic if (occurrence.getTopic() != this) return; // Notify listeners fireEvent(TopicIF.EVENT_REMOVE_OCCURRENCE, null, occurrence); // Unset topic property ((Occurrence)occurrence).setTopic(null); // Notify transaction valueRemoved(LF_occurrences, occurrence, false); } public Collection<AssociationRoleIF> getRoles() { return this.<AssociationRoleIF>loadCollectionField(LF_roles); } public Collection<AssociationRoleIF> getRolesByType(TopicIF roletype) { if (roletype == null) throw new NullPointerException("Role type cannot be null."); // if roles already loaded filter by role type if (isLoaded(LF_roles)) { Collection<AssociationRoleIF> roles = (Collection<AssociationRoleIF>) getValue(LF_roles); if (roles.isEmpty()) return (Collection<AssociationRoleIF>) Collections.EMPTY_SET; Collection<AssociationRoleIF> result = new CompactHashSet<AssociationRoleIF>(); for (AssociationRoleIF role : roles) { if (role.getType() == roletype) result.add(role); } return result; } else { // lookup roles by type TopicMap tm = (TopicMap)getTopicMap(); if (tm == null) throw new ConstraintViolationException("Cannot retrieve roles by type when topic isn't attached to a topic map."); return tm.getRolesByType(this, roletype); } } public Collection<AssociationRoleIF> getRolesByType(TopicIF roletype, TopicIF assoc_type) { if (roletype == null) throw new NullPointerException("Role type cannot be null."); if (assoc_type == null) throw new NullPointerException("Association type cannot be null."); // if roles already loaded filter by role type if (isLoaded(LF_roles)) { Collection<AssociationRoleIF> roles = (Collection<AssociationRoleIF>) getValue(LF_roles); if (roles.isEmpty()) return (Collection<AssociationRoleIF>) Collections.EMPTY_SET; Collection<AssociationRoleIF> result = new CompactHashSet<AssociationRoleIF>(); for (AssociationRoleIF role : roles) { if (role.getType() == roletype) { AssociationIF assoc = role.getAssociation(); if (assoc != null && assoc.getType() == assoc_type) result.add(role); } } return result; } else { // lookup roles by type if (roletype == null) { TopicMap tm = (TopicMap) getTopicMap(); if (tm == null) throw new ConstraintViolationException("Cannot retrieve roles by type when topic isn't attached to a topic map."); return tm.getRolesByType(this, roletype, assoc_type); } else { TopicMap tm = (TopicMap)roletype.getTopicMap(); return tm.getRolesByType(this, roletype, assoc_type); } } } public Collection<AssociationIF> getAssociations() { return ((TopicMap)getTopicMap()).getAssocations(this); } public Collection<AssociationIF> getAssociationsByType(TopicIF type) { return ((TopicMap)getTopicMap()).getAssociationsByType(this, type); } public void merge(TopicIF topic) { CrossTopicMapException.check(topic, this); net.ontopia.topicmaps.utils.MergeUtils.mergeInto(this, topic); } /** * INTERNAL: Adds the association role to the set of association * roles in which the topic participates. */ void addRole(AssociationRoleIF assoc_role) { // Notify transaction valueAdded(LF_roles, assoc_role, false); } /** * INTERNAL: Removes the association role from the set of * association roles in which the topic participates. */ void removeRole(AssociationRoleIF assoc_role) { // Notify transaction valueRemoved(LF_roles, assoc_role, false); } public void remove() { TopicMap topicmap = (TopicMap)getTopicMap(); if (topicmap != null) topicmap.removeTopic(this); } public Collection<TopicIF> getTypes() { return this.<TopicIF>loadCollectionField(LF_types); } public void addType(TopicIF type) { if (type == null) throw new NullPointerException("null is not a valid argument."); CrossTopicMapException.check(type, this); // Notify listeners fireEvent(TopicIF.EVENT_ADD_TYPE, type, null); // Notify transaction valueAdded(LF_types, type, true); } public void removeType(TopicIF type) { if (type == null) throw new NullPointerException("null is not a valid argument."); CrossTopicMapException.check(type, this); // Notify listeners fireEvent(TopicIF.EVENT_REMOVE_TYPE, null, type); // Notify transaction valueRemoved(LF_types, type, true); } public ReifiableIF getReified() { String reifiedId = this.<String>loadField(Topic.LF_reified); if (reifiedId == null) return null; return (ReifiableIF) getTopicMap().getObjectById(reifiedId); } void setReified(ReifiableIF reified) { ReifiableIF oldReified = getReified(); if (ObjectUtils.different(oldReified, reified)) { String reifiedId = (reified == null ? null : reified.getObjectId()); valueChanged(LF_reified, reifiedId, true); } } // --------------------------------------------------------------------------- // Misc. methods // --------------------------------------------------------------------------- public String toString() { return ObjectStrings.toString("rdbms.Topic", (TopicIF) this); } @Override public void syncAfterMerge(IdentityIF source, IdentityIF target) { syncFieldsAfterMerge(source, target, LF_types, LF_names, LF_occurrences, LF_roles, LF_reified); } }