List<RelatedAssociationModel> fetchSequence(Topic typeTopic) {
   try {
     List<RelatedAssociationModel> sequence = new ArrayList();
     // find sequence start
     RelatedAssociation assocDef =
         typeTopic.getRelatedAssociation(
             "dm4.core.aggregation",
             "dm4.core.type",
             "dm4.core.sequence_start",
             null,
             false,
             false); // othersAssocTypeUri=null
     // fetch sequence segments
     if (assocDef != null) {
       sequence.add(assocDef.getModel());
       while ((assocDef =
               assocDef.getRelatedAssociation(
                   "dm4.core.sequence", "dm4.core.predecessor", "dm4.core.successor"))
           != null) {
         //
         sequence.add(assocDef.getModel());
       }
     }
     //
     return sequence;
   } catch (Exception e) {
     throw new RuntimeException(
         "Fetching sequence for type \"" + typeTopic.getUri() + "\" failed", e);
   }
 }
 private void storeConfigTopic(RoleModel configurable, TopicModel configTopic) {
   // Note: null is passed as clientState. Called only (indirectly) from a migration ### FIXME: is
   // this true?
   // and in a migration we have no clientState anyway.
   Topic topic = dms.createTopic(configTopic, null); // clientState=null
   dms.createAssociation(
       "dm4.core.aggregation",
       configurable,
       new TopicRoleModel(topic.getId(), "dm4.core.view_config"));
 }
 private void checkAssociationType(String assocTypeUri, Topic typeTopic) {
   if (typeTopic == null) {
     throw new RuntimeException("Association type \"" + assocTypeUri + "\" not found");
   } else if (!typeTopic.getTypeUri().equals("dm4.core.assoc_type")) {
     throw new RuntimeException(
         "URI \""
             + assocTypeUri
             + "\" refers to a \""
             + typeTopic.getTypeUri()
             + "\" when the caller expects a \"dm4.core.assoc_type\"");
   }
 }
 private void checkTopicType(String topicTypeUri, Topic typeTopic) {
   if (typeTopic == null) {
     throw new RuntimeException("Topic type \"" + topicTypeUri + "\" not found");
   } else if (!typeTopic.getTypeUri().equals("dm4.core.topic_type")
       && !typeTopic.getTypeUri().equals("dm4.core.meta_type")
       && !typeTopic.getTypeUri().equals("dm4.core.meta_meta_type")) {
     throw new RuntimeException(
         "URI \""
             + topicTypeUri
             + "\" refers to a \""
             + typeTopic.getTypeUri()
             + "\" when the caller expects a \"dm4.core.topic_type\"");
   }
 }
 private ViewConfigurationModel fetchTypeViewConfig(Topic typeTopic) {
   try {
     // Note: othersTopicTypeUri=null, the view config's topic type is unknown (it is
     // client-specific)
     ResultSet<RelatedTopic> configTopics =
         typeTopic.getRelatedTopics(
             "dm4.core.aggregation",
             "dm4.core.type",
             "dm4.core.view_config",
             null,
             true,
             false,
             0,
             null);
     return new ViewConfigurationModel(DeepaMehtaUtils.toTopicModels(configTopics.getItems()));
   } catch (Exception e) {
     throw new RuntimeException(
         "Fetching view configuration for type \"" + typeTopic.getUri() + "\" failed", e);
   }
 }
 // ### TODO: unify with next method
 private TopicTypeModel fetchTopicType(String topicTypeUri) {
   Topic typeTopic = dms.getTopic("uri", new SimpleValue(topicTypeUri), false, null);
   checkTopicType(topicTypeUri, typeTopic);
   //
   // 1) fetch type components
   String dataTypeUri = fetchDataTypeTopic(typeTopic.getId(), topicTypeUri, "topic type").getUri();
   Set<IndexMode> indexModes = fetchIndexModes(typeTopic.getId());
   List<AssociationDefinitionModel> assocDefs = fetchAssociationDefinitions(typeTopic);
   List<String> labelConfig = fetchLabelConfig(assocDefs);
   ViewConfigurationModel viewConfig = fetchTypeViewConfig(typeTopic);
   //
   // 2) build type model
   TopicTypeModel topicType =
       new TopicTypeModel(
           typeTopic.getModel(), dataTypeUri, indexModes, assocDefs, labelConfig, viewConfig);
   //
   // 3) put in type cache
   putInTypeCache(topicType);
   //
   return topicType;
 }
 private void deleteSequence(Topic typeTopic) {
   List<RelatedAssociationModel> sequence = fetchSequence(typeTopic);
   logger.info(
       "### Deleting "
           + sequence.size()
           + " sequence segments of type \""
           + typeTopic.getUri()
           + "\"");
   for (RelatedAssociationModel assoc : sequence) {
     long assocId = assoc.getRelatingAssociationModel().getId();
     dms.deleteAssociation(assocId, null); // clientState=null
   }
 }
 private Map<Long, AssociationDefinitionModel> fetchAssociationDefinitionsUnsorted(
     Topic typeTopic) {
   Map<Long, AssociationDefinitionModel> assocDefs = new HashMap();
   //
   // 1) fetch part topic types
   // Note: we must set fetchRelatingComposite to false here. Fetching the composite of association
   // type
   // Composition Definition would cause an endless recursion. Composition Definition is defined
   // through
   // Composition Definition itself (child types "Include in Label", "Ordered").
   // Note: "othersTopicTypeUri" is set to null. We want consider "dm4.core.topic_type" and
   // "dm4.core.meta_type"
   // as well (the latter required e.g. by dm4-mail) ### TODO: add a getRelatedTopics() method that
   // takes a list
   // of topic types.
   ResultSet<RelatedTopic> partTypes =
       typeTopic.getRelatedTopics(
           asList("dm4.core.aggregation_def", "dm4.core.composition_def"),
           "dm4.core.whole_type",
           "dm4.core.part_type",
           null,
           false,
           false,
           0,
           null);
   // othersTopicTypeUri=null, fetchComposite=false, fetchRelatingComposite=false, clientState=null
   //
   // 2) create association definitions
   // Note: the returned map is an intermediate, hashed by ID. The actual type model is
   // subsequently build from it by sorting the assoc def's according to the sequence IDs.
   for (RelatedTopic partType : partTypes) {
     AssociationDefinitionModel assocDef =
         fetchAssociationDefinition(
             partType.getAssociation(), typeTopic.getUri(), partType.getUri());
     assocDefs.put(assocDef.getId(), assocDef);
   }
   return assocDefs;
 }
 private List<AssociationDefinitionModel> fetchAssociationDefinitions(Topic typeTopic) {
   Map<Long, AssociationDefinitionModel> assocDefs =
       fetchAssociationDefinitionsUnsorted(typeTopic);
   List<RelatedAssociationModel> sequence = fetchSequence(typeTopic);
   // error check
   if (assocDefs.size() != sequence.size()) {
     throw new RuntimeException(
         "DB inconsistency: type \""
             + typeTopic.getUri()
             + "\" has "
             + assocDefs.size()
             + " association definitions but in sequence are "
             + sequence.size());
   }
   //
   return sortAssocDefs(assocDefs, DeepaMehtaUtils.idList(sequence));
 }