/* * #! * 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.utils; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.topicmaps.core.AssociationIF; import net.ontopia.topicmaps.core.AssociationRoleIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.TypedIF; import net.ontopia.topicmaps.core.index.ClassInstanceIndexIF; /** * INTERNAL: Utilities for working with class-instance relationships. */ public class ClassInstanceUtils { /** * INTERNAL: Replaces all class-instance associations in a topic map * by direct references from the topics in question to their types. * Only associations that use the PSIs defined in XTM 1.0, that * match the templates exactly, that are not reified, and that are * not scoped are replaced. * @since 1.2.3 */ public static void resolveAssociations1(TopicMapIF topicmap) { resolveAssociations(topicmap, PSI.getXTMClassInstance(), PSI.getXTMClass(), PSI.getXTMInstance()); } /** * INTERNAL: Replaces all class-instance associations using the XTM * 2.0 PSIs in a topic map by direct references from the topics in * question to their types. Only associations that use the PSIs * defined in XTM 2.0, that match the templates exactly, that are * not reified, and that are not scoped are replaced. */ public static void resolveAssociations2(TopicMapIF topicmap) { resolveAssociations(topicmap, PSI.getSAMTypeInstance(), PSI.getSAMType(), PSI.getSAMInstance()); } /** * INTERNAL: The actual implementation, shared across PSI sets. */ private static void resolveAssociations(TopicMapIF topicmap, LocatorIF assoctype, LocatorIF typetype, LocatorIF insttype) { // first, resolve the PSIs TopicIF classinstance = topicmap.getTopicBySubjectIdentifier(assoctype); TopicIF klass = topicmap.getTopicBySubjectIdentifier(typetype); TopicIF instance = topicmap.getTopicBySubjectIdentifier(insttype); if (classinstance == null || klass == null || instance == null) return; // then, get the index ClassInstanceIndexIF typeIndex = (ClassInstanceIndexIF) topicmap.getIndex("net.ontopia.topicmaps.core.index.ClassInstanceIndexIF"); // then, look over those associations Iterator<AssociationIF> it = typeIndex.getAssociations(classinstance).iterator(); while (it.hasNext()) { AssociationIF assoc = it.next(); if (assoc.getRoles().size() != 2 || !assoc.getScope().isEmpty() || assoc.getReifier() != null) continue; TopicIF klasstopic = null; TopicIF insttopic = null; Iterator<AssociationRoleIF> it2 = assoc.getRoles().iterator(); while (it2.hasNext()) { AssociationRoleIF role = it2.next(); TopicIF type = role.getType(); if (type == null) break; else if (type.equals(klass)) klasstopic = role.getPlayer(); else if (type.equals(instance)) insttopic = role.getPlayer(); else break; } if (klasstopic == null || insttopic == null) continue; insttopic.addType(klasstopic); assoc.remove(); } } /** * INTERNAL: Returns true if the TypedIF object is an instance the * given type. */ public static boolean isInstanceOf(TypedIF typed, TopicIF type) { return (type != null && type.equals(typed.getType())); } /** * INTERNAL: Returns true if the TopicIF object is an instance * the given type. */ public static boolean isInstanceOf(TopicIF topic, TopicIF type) { return (topic.getTypes().contains(type)); } /** * INTERNAL: Returns the typed objects that are instances of the given type. */ public static Collection getInstancesOf(Collection typed, TopicIF type) { Collection result = new ArrayList(); // Loop over the typed objects to see if they're instances of the type Iterator iter = typed.iterator(); while (iter.hasNext()) { Object object = iter.next(); if (object instanceof TypedIF) { if (isInstanceOf((TypedIF)object, type)) result.add(object); } else { if (isInstanceOf((TopicIF)object, type)) result.add(object); } } return result; } /** * INTERNAL: Returns the topics that are the type/class topic of the * typed objects. */ public static Collection getTypes(Collection typed) { return getTypes(typed, new ArrayList()); } /** * INTERNAL: Modifies the accumulated collection to also include the * types of the typed objects. */ public static Collection getTypes(Collection typed, Collection accumulated) { // Loop over typed objects Iterator iter = typed.iterator(); while (iter.hasNext()) { Object object = iter.next(); if (object instanceof TypedIF) accumulated.add(((TypedIF)object).getType()); else accumulated.add(((TopicIF)object).getTypes()); } return accumulated; } /** * INTERNAL: Returns a Map containing the typed objects keyed by type. The * value of a map entry is always a Collection instance. */ public static Map getTypeMap(Collection typed) { return getTypeMap(typed, new HashMap()); } /** * INTERNAL: Modifies the accumulated map to also include the type map * of the typed objects. The value of a map entry is always a * Collection instance. */ public static Map getTypeMap(Collection typed, Map accumulated) { // Loop over the typed objects Iterator iter = typed.iterator(); while (iter.hasNext()) { Object object = iter.next(); // Check to see if object implements TypedIF or TopicIF TopicIF type; if (object instanceof TypedIF) { // TypedIF type = ((TypedIF)object).getType(); if (!accumulated.containsKey(type)) accumulated.put(type, new HashSet()); ((Set)accumulated.get(type)).add(object); } else { // TopicIF Iterator<TopicIF> iter2 = ((TopicIF)object).getTypes().iterator(); while (iter2.hasNext()) { type = iter2.next(); if (!accumulated.containsKey(type)) accumulated.put(type, new HashSet()); ((Set)accumulated.get(type)).add(object); } } } return accumulated; } }