# Copyright: Copyright 2009 Topic Maps Lab, University of Leipzig. # License: Apache License, Version 2.0 module RTM class MergeException < Exception; end class TopicMergeException < MergeException; end module Merging module ReWrap protected def merge_rewrap(other) # let the wrapper point to the new object old_getobj = other.__getobj__ other.__setobj__(self.__getobj__) if self.respond_to?(:__getobj__) && other.respond_to?(:__setobj__) # and destroy the old one old_getobj.reload __getobj__.reload old_getobj.destroy end end module MergeItemIdentifiers protected def merge_item_identifiers(other) #self.item_identifiers.add_all other.item_identifiers RTM::AR::TMDM::ItemIdentifier.move_all( ["topic_map_construct_id", other.__getobj__.id, self.__getobj__.id], ["topic_map_construct_type", other.__getobj__.class.name, self.__getobj__.class.name] ) end end module MergeReifiable include MergeItemIdentifiers include ReWrap protected def merge_reifiable(other) if other.reifier && self.reifier self.reifier.merge(other.reifier) elsif other.reifier self.reifier = other.reifier end end end module Association include Merging::MergeReifiable def merge(other) # The procedure for merging two association items A and B is given below. # 1. Create a new association item, C. # -> we will instead just modify a # 2. Set C's [type] property to the value of A's [type] property. B's value is equal to that of A and need not be taken into account. # 3. Set C's [scope] property to the value of A's [scope] property. B's value is equal to that of A and need not be taken into account. # 4. Set C's [roles] property to the value of A's [roles] property. B's value is equal to that of A and need not be taken into account. # -> nothing to do till here # 5. Set C's [reifier] property to the value of A's [reifier] property if it is not null, and to the value of B's [reifier] property if A's property is null. If both A and B have non-null values, the topic items shall be merged, and the topic item resulting from the merge set as the value of C's [reifier] property. self.merge_reifiable other # 6. Set C's [item identifiers] property to the union of the values of A's and B's [item identifiers] properties. self.merge_item_identifiers other # 7. Remove A and B from the [associations] property of the topic map item in their [parent] properties, and add C. #self.parent.associations.remove other # let the wrapper point to the new object #other.__setobj__(self.__getobj__) if self.respond_to?(:__getobj__) && other.respond_to?(:__setobj__) self.merge_rewrap other self end end module Role include Merging::MergeReifiable def merge(other) # The procedure for merging two association role items A and B is given below. # -> we will instead just modify a # 1. Create a new association role item, C. # 2. Set C's [player] property to the value of A's [player] property. B's value is equal to that of A and need not be taken into account. # 3. Set C's [type] property to the value of A's [type] property. B's value is equal to that of A and need not be taken into account. # -> nothing to do till here # 4. Set C's [item identifiers] property to the union of the values of A's and B's [item identifiers] properties. self.merge_item_identifiers other # 5. Set C's [reifier] property to the value of A's [reifier] property if it is not null, # and to the value of B's [reifier] property if A's property is null. # If both A and B have non-null values, the topic items shall be merged, # and the topic item resulting from the merge set as the value of C's [reifier] property. self.merge_reifiable other # 6. Remove A and B from the [roles] property of the association item in their [parent] properties, and add C. #self.parent.roles.remove other #puts "#{self.parent.object_id} and #{other.parent.object_id}" # let the wrapper point to the new object #other.__setobj__(self.__getobj__) if self.respond_to?(:__getobj__) && other.respond_to?(:__setobj__) self.merge_rewrap other self end end module Occurrence include Merging::MergeReifiable def merge(other) # 1. Create a new occurrence item, C. # -> we will instead just modify a # 2. Set C's [value] property to the value of A's [value] property. B's value is equal to that of A and need not be taken into account. # 3. Set C's [datatype] property to the value of A's [datatype] property. B's value is equal to that of A and need not be taken into account. # 4. Set C's [scope] property to the value of A's [scope] property. B's value is equal to that of A and need not be taken into account. # 5. Set C's [type] property to the value of A's [type] property. B's value is equal to that of A and need not be taken into account. # -> nothing to do till here # 6. Set C's [reifier] property to the value of A's [reifier] property if it is not null, and to the value of B's [reifier] property if A's property is null. If both A and B have non-null values, the topic items shall be merged, and the topic item resulting from the merge set as the value of C's [reifier] property. self.merge_reifiable other # 7. Set C's [item identifiers] property to the union of the values of A's and B's [item identifiers] properties. self.merge_item_identifiers other # 8. Remove A and B from the [occurrences] property of the topic item in their [parent] properties, and add C. #self.parent.occurrences.remove other # let the wrapper point to the new object #other.__setobj__(self.__getobj__) if self.respond_to?(:__getobj__) && other.respond_to?(:__setobj__) self.merge_rewrap other self end end module Topic include Merging::ReWrap include Merging::MergeItemIdentifiers def merge(other) return unless other # The procedure for merging two topic items A and B # -> we will instead just modify a # (whose [parent] properties shall contain the same topic map item) is given below. raise TopicMergeException, "Both topics must belong to the same topic map!" if self.parent.__getobj__ != other.parent.__getobj__ # It is an error if A and B both have non-null values in their [reified] properties which are different. raise TopicMergeException, "The Topics must not reify different things." if self.reified && other.reified && self.reified.__getobj__ != other.reified.__getobj__ # 1. Create a new topic item C. # 2. Replace A by C wherever it appears in one of the following properties # of an information item: [topics], [scope], [type], [player], and [reifier]. # -> nothing to do here # 3. Repeat for B. # [topics] # done below, in rewrap # [scope] RTM::AR::TMDM::ScopedObjectsTopic.move_all(["topic_id", other.__getobj__.id, self.__getobj__.id]) # [type] RTM::AR::TMDM::Association.move_all(["ttype_id", other.__getobj__.id, self.__getobj__.id]) RTM::AR::TMDM::Role.move_all(["ttype_id", other.__getobj__.id, self.__getobj__.id]) RTM::AR::TMDM::Name.move_all(["ttype_id", other.__getobj__.id, self.__getobj__.id]) RTM::AR::TMDM::Occurrence.move_all(["ttype_id", other.__getobj__.id, self.__getobj__.id]) # [player] RTM::AR::TMDM::AssociationRole.move_all(["topic_id", other.__getobj__.id, self.__getobj__.id]) # [reifier] if other.reified self.reified = other.reified end # 4. Set C's [topic names] property to the union of the values of A and B's [topic names] properties. #self.names.add_all other.names count = RTM::AR::TMDM::Name.move_all(["topic_id", other.__getobj__.id, self.__getobj__.id]) if count != 0 && count != names.size names.each_with_index do |n,i| (i+1).upto(names.size-1) do |j| if n == names[j] n.merge names[j] end end end end # 5. Set C's [occurrences] property to the union of the values of A and B's [occurrences] properties. #self.occurrences.add_all other.occurrences RTM::AR::TMDM::Occurrence.move_all(["topic_id", other.__getobj__.id, self.__getobj__.id]) if count != 0 && count != occurrences.size occurrences.each_with_index do |o,i| (i+1).upto(occurrences.size-1) do |j| if o == occurrences[j] o.merge occurrences[j] end end end end # 6. Set C's [subject identifiers] property to the union of the values of A and B's [subject identifiers] properties. #self.subject_identifiers.add_all other.subject_identifiers RTM::AR::TMDM::SubjectIdentifier.move_all(["topic_id", other.__getobj__.id, self.__getobj__.id]) # 7. Set C's [subject locators] property to the union of the values of A and B's [subject locators] properties. #self.subject_locators.add_all other.subject_locators RTM::AR::TMDM::SubjectLocator.move_all(["topic_id", other.__getobj__.id, self.__getobj__.id]) # 8. Set C's [item identifiers] property to the union of the values of A and B's [item identifiers] properties. #self.item_identifiers.add_all other.item_identifiers #RTM::AR::TMDM::ItemIdentifier.update_all "topic_map_construct_id = #{self.__getobj__.id}, topic_map_construct_type = '#{self.__getobj__.class.name}'", "topic_map_construct_id = #{other.__getobj__.id} and topic_map_construct_type = '#{other.__getobj__.class.name}'" RTM::AR::TMDM::ItemIdentifier.move_all( ["topic_map_construct_id", other.__getobj__.id, self.__getobj__.id], ["topic_map_construct_type", other.__getobj__.class.name, self.__getobj__.class.name] ) self.merge_rewrap other self end alias :merge_in :merge end module TopicMap include Merging::MergeReifiable def merge(other) # other:TopicMap self.topics.add_all other.topics self.associations.add_all other.associations self.merge_reifiable other self.merge_item_identifiers other self.merge_rewrap other self end alias :merge_in :merge end module Name def merge(other) # The procedure for merging two topic name items A and B is given below. # -> we will instead just modify a # 1. Create a new topic name item C. # 2. Set C's [value] property to the value of the [value] property of A. B's value is equal that of A and need not be taken into account. # 3. Set C's [type] property to the value of the [type] property of A. B's value is equal that of A and need not be taken into account. # 4. Set C's [scope] property to the value of the [scope] property of A. B's value is equal that of A and need not be taken into account. # -> nothing to do till here # 5. Set C's [variants] property to the union of the [variants] properties of A and B. #self.variants.add_all other.variants count = RTM::AR::TMDM::Variant.move_all(["name_id", other.__getobj__.id, self.__getobj__.id]) if count != 0 && count != variants.size variants.each_with_index do |v,i| (i+1).upto(variants.size-1) do |j| if v == variants[j] v.merge variants[j] end end end end # 6. Set C's [reifier] property to the value of A's [reifier] property if it is not null, and to the value of B's [reifier] property if A's property is null. If both A and B have non-null values, the topic items shall be merged, and the topic item resulting from the merge be set as the value of C's [reifier] property. self.merge_reifiable other # 7. Set C's [item identifiers] property to the union of the value of the [item identifiers] properties of A and B. self.merge_item_identifiers other # 8. Remove A and B from the [topic names] property of the topic item in their [parent] properties, and add C. #self.parent.names.remove other # let the wrapper point to the new object #other.__setobj__(self.__getobj__) if self.respond_to?(:__getobj__) && other.respond_to?(:__setobj__) self.merge_rewrap other self end end module Variant include Merging::MergeReifiable def merge(other) #The procedure for merging two variant items A and B is given below. # -> we will instead just modify a # 1. Create a new variant item, C. # 2. Set C's [value] property to the value of A's [value] property. B's value is equal to that of A and need not be taken into account. # 3. Set C's [datatype] property to the value of A's [datatype] property. B's value is equal to that of A and need not be taken into account. # 4. Set C's [scope] property to the value of A's [scope] property. B's value is equal to that of A and need not be taken into account. # -> nothing to do till here # 5. Set C's [reifier] property to the value of A's [reifier] property if it is not null, and to the value of B's [reifier] property if A's property is null. If both A and B have non-null values, the topic items shall be merged, and the topic item resulting from the merge set as the value of C's [reifier] property. self.merge_reifiable other # 6. Set C's [item identifiers] property to the union of the values of A's and B's [item identifiers] properties. self.merge_item_identifiers other # 7. Remove A and B from the [variants] property of the topic name item in their [parent] properties, and add C. #self.parent.variants.remove other # let the wrapper point to the new object #other.__setobj__(self.__getobj__) if self.respond_to?(:__getobj__) && other.respond_to?(:__setobj__) self.merge_rewrap other self end end RTM.register_extension( self ) end end