/* * #! * Ontopoly Editor * #- * 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 ontopoly.utils; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.query.core.DeclarationContextIF; import net.ontopia.topicmaps.query.core.InvalidQueryException; import net.ontopia.topicmaps.query.core.QueryProcessorIF; import net.ontopia.topicmaps.query.core.QueryResultIF; import net.ontopia.topicmaps.utils.TopicStringifiers; import net.ontopia.utils.OntopiaRuntimeException; import ontopoly.model.PSI; import ontopoly.model.TopicMap; import ontopoly.model.TopicType; import ontopoly.models.TopicMapModel; import ontopoly.pojos.TopicNode; public class TreeModels { public static TreeModel createEmptyTreeModel() { return new DefaultTreeModel(new DefaultMutableTreeNode("<root>")); } public static TreeModel createTopicTypesTreeModel(TopicMap tm, boolean isAnnotationEnabled, boolean isAdminEnabled) { StringBuilder sb = new StringBuilder(); sb.append("using on for i\"http://psi.ontopia.net/ontology/\" "); sb.append("using xtm for i\"http://www.topicmaps.org/xtm/1.0/core.xtm#\" "); sb.append("select $P, $C from "); if (isAnnotationEnabled) sb.append("{ instance-of($C, on:ontology-type) | $C = on:topic-map, topic($C) | "); sb.append("instance-of($C, on:topic-type), "); if (!isAdminEnabled) sb.append("not(direct-instance-of($C, on:system-topic)), "); sb.append("{ xtm:superclass-subclass($C : xtm:subclass, $P : xtm:superclass), instance-of($P, on:topic-type)"); if (!isAdminEnabled) sb.append(", not(direct-instance-of($P, on:system-topic))"); sb.append(" }"); if (isAnnotationEnabled) sb.append("}"); sb.append(" order by $P, $C?"); final String topicMapId = tm.getId(); Map<String,?> params = Collections.emptyMap(); return new QueryTreeModel(tm, sb.toString(), params) { @Override protected DefaultMutableTreeNode createTreeNode(Object o) { return new DefaultMutableTreeNode(new TopicNode(topicMapId, ((TopicIF)o).getObjectId())); } }; } public static TreeModel createOccurrenceTypesTreeModel(TopicMap tm, boolean isAdminEnabled) { return createTypesTreeModel(tm, "on:occurrence-type", isAdminEnabled); } public static TreeModel createAssociationTypesTreeModel(TopicMap tm, boolean isAdminEnabled) { return createTypesTreeModel(tm, "on:association-type", isAdminEnabled); } public static TreeModel createRoleTypesTreeModel(TopicMap tm, boolean isAdminEnabled) { return createTypesTreeModel(tm, "on:role-type", isAdminEnabled); } public static TreeModel createNameTypesTreeModel(TopicMap tm, boolean isAdminEnabled) { return createTypesTreeModel(tm, "on:name-type", isAdminEnabled); } protected static TreeModel createTypesTreeModel(TopicMap tm, String typePSI, boolean isAdminEnabled) { StringBuilder sb = new StringBuilder(); sb.append("using on for i\"http://psi.ontopia.net/ontology/\" "); sb.append("using xtm for i\"http://www.topicmaps.org/xtm/1.0/core.xtm#\" "); sb.append("select $P, $C from "); sb.append("instance-of($C, ").append(typePSI).append("), "); if (!isAdminEnabled) sb.append("not(direct-instance-of($C, on:system-topic)), "); sb.append("{ xtm:superclass-subclass($C : xtm:subclass, $P : xtm:superclass), instance-of($P, ").append(typePSI).append(")"); if (!isAdminEnabled) sb.append(", not(direct-instance-of($P, on:system-topic))"); sb.append(" }"); sb.append(" order by $P, $C?"); final String topicMapId = tm.getId(); Map<String,?> params = Collections.emptyMap(); return new QueryTreeModel(tm, sb.toString(), params) { @Override protected DefaultMutableTreeNode createTreeNode(Object o) { return new DefaultMutableTreeNode(new TopicNode(topicMapId, ((TopicIF)o).getObjectId())); } }; } private static class HierarchyDefinition { TopicIF atype; TopicIF prtype; TopicIF crtype; Collection<TopicIF> ptypes = new HashSet<TopicIF>(); Collection<TopicIF> ctypes = new HashSet<TopicIF>(); HierarchyDefinition(TopicIF atype, TopicIF prtype, TopicIF crtype) { this.atype = atype; this.prtype = prtype; this.crtype = crtype; } public boolean equals(Object other) { HierarchyDefinition o = (HierarchyDefinition)other; return atype.equals(o.atype) && prtype.equals(o.prtype) && crtype.equals(o.crtype); } public int hashCode() { return atype.hashCode() + prtype.hashCode() + crtype.hashCode(); } } public static TreeModel createInstancesTreeModel(TopicType topicType, final boolean isAdminEnabled) { DefaultMutableTreeNode root = new DefaultMutableTreeNode("<root>"); if (topicType != null) { TopicMap topicMap = topicType.getTopicMap(); QueryProcessorIF qp = topicMap.getQueryProcessor(); DeclarationContextIF dc = topicMap.getDeclarationContext(); String query = "using on for i\"http://psi.ontopia.net/ontology/\" " + "using hierarchy for i\"http://www.techquila.com/psi/hierarchy/#\" " + "select $ATYPE, $CRT, $CRPT, $PRT, $PRPT from " + "on:forms-hierarchy-for($TTYPE : on:topic-type, $ATYPE : on:association-type), " + "on:has-association-type($ATYPE : on:association-type, $AF : on:association-field), " + "on:has-association-field($AF : on:association-field, $RF1 : on:role-field), " + "on:has-role-type($RF1 : on:role-field, $PRT : on:role-type), " + "instance-of($PRT, hierarchy:superordinate-role-type), " + "on:has-field($RF1 : on:field-definition, $PRPT : on:field-owner), " + "on:has-association-field($AF : on:association-field, $RF2 : on:role-field), " + "on:has-role-type($RF2 : on:role-field, $CRT : on:role-type), " + "instance-of($CRT, hierarchy:subordinate-role-type), " + "on:has-field($RF2 : on:field-definition, $CRPT : on:field-owner) " + "order by $ATYPE, $PRT, $CRT" + "?"; // retrieve hierarchical definitions Map<HierarchyDefinition,HierarchyDefinition> hds = new HashMap<HierarchyDefinition,HierarchyDefinition>(); Map<TopicIF,Set<HierarchyDefinition>> hd_ctypes = new HashMap<TopicIF,Set<HierarchyDefinition>>(); try { Map<String,?> params = Collections.emptyMap(); QueryResultIF qr = qp.execute(query, params, dc); try { while (qr.next()) { TopicIF atype = (TopicIF)qr.getValue(0); TopicIF crtype = (TopicIF)qr.getValue(1); TopicIF prtype = (TopicIF)qr.getValue(3); HierarchyDefinition hd = new HierarchyDefinition(atype, prtype, crtype); if (hds.containsKey(hd)) hd = hds.get(hd); else hds.put(hd, hd); TopicIF crpt = (TopicIF)qr.getValue(2); TopicIF prpt = (TopicIF)qr.getValue(4); hd.ctypes.add(crpt); hd.ptypes.add(prpt); if (!hd_ctypes.containsKey(crpt)) hd_ctypes.put(crpt, new HashSet<HierarchyDefinition>()); hd_ctypes.get(crpt).add(hd); } } finally { qr.close(); } // generate hierarchical query Map<TopicIF,StringBuilder> existingRules = new LinkedHashMap<TopicIF,StringBuilder>(); TopicIF topicTypeIf = topicType.getTopicIF(); StringBuilder sb = new StringBuilder(); sb.append("select $P, $C from\n"); sb.append(createHierarchyRuleFor(topicTypeIf, "P", "C", "B", existingRules, hd_ctypes)); // if (!isAdminEnabled) // sb.append(", not({direct-instance-of($P, on:system-topic) || direct-instance-of($C, on:system-topic)})"); sb.append("\norder by $P, $C?"); Iterator<StringBuilder> riter = existingRules.values().iterator(); while (riter.hasNext()) { sb.insert(0, riter.next()); } String hquery = sb.toString(); final String topicMapId = topicMap.getId(); final TopicMapModel topicMapModel = new TopicMapModel(topicMap); Map<String,TopicIF> hqparams = Collections.singletonMap("topicType", topicTypeIf); return new QueryTreeModel(topicType.getTopicMap(), hquery, hqparams) { @Override protected boolean filter(Object p, Object c) { if (isAdminEnabled) return true; // filter out system topics TopicIF systemTopic = topicMapModel.getTopicMap().getTopicMapIF().getTopicBySubjectIdentifier(PSI.ON_SYSTEM_TOPIC); if (p != null) { TopicIF pt = (TopicIF)p; if (pt.getTypes().contains(systemTopic)) return false; } if (c != null) { TopicIF ct = (TopicIF)c; if (ct.getTypes().contains(systemTopic)) return false; } return true; } @Override protected DefaultMutableTreeNode createTreeNode(Object o) { return new DefaultMutableTreeNode(new TopicNode(topicMapId, ((TopicIF)o).getObjectId())); } }; } catch (InvalidQueryException e) { throw new OntopiaRuntimeException(e); } } return new DefaultTreeModel(root); } private static StringBuilder createHierarchyRuleFor(TopicIF topicType, String pVar, String cVar, String bVar, Map<TopicIF,StringBuilder> existingRules, Map<TopicIF,Set<HierarchyDefinition>> hd_ctypes) { if (!existingRules.containsKey(topicType)) { StringBuilder sb = new StringBuilder(); existingRules.put(topicType, sb); // create rule for type sb.append("/* ").append(TopicStringifiers.toString(topicType)).append(" */\n"); sb.append("hierarchy-for-").append(topicType.getObjectId()).append("($P, $C, $B) :- \n"); sb.append("instance-of($B, @").append(topicType.getObjectId()).append("),\n"); Collection<HierarchyDefinition> hds = hd_ctypes.get(topicType); if (hds != null && !hds.isEmpty()) { sb.append(createStepPredicates(hds, existingRules, hd_ctypes)); } else { sb.append("$B = $C, { not($P = $B) }"); // do weird logic to get $P bound } sb.append(".\n"); } // call rule return new StringBuilder().append("hierarchy-for-").append(topicType.getObjectId()) .append("($").append(pVar).append(", $").append(cVar).append(", $").append(bVar).append(")"); } private static StringBuilder createStepPredicates(Collection<HierarchyDefinition> hds, Map<TopicIF,StringBuilder> existingRules, Map<TopicIF,Set<HierarchyDefinition>> hd_ctypes) { StringBuilder sb = new StringBuilder(); // call parent rules sb.append("{ "); Iterator<HierarchyDefinition> hiter = hds.iterator(); while (hiter.hasNext()) { HierarchyDefinition hd = hiter.next(); sb.append("$B = $C, "); sb.append("{ ").append("@").append(hd.atype.getObjectId()) .append("($C").append(" : @").append(hd.crtype.getObjectId()) .append(", $P").append(" : @").append(hd.prtype.getObjectId()).append(")").append(" } |\n"); sb.append("@").append(hd.atype.getObjectId()) .append("($B").append(" : @").append(hd.crtype.getObjectId()) .append(", $X").append(" : @").append(hd.prtype.getObjectId()).append("), "); sb.append(createStepPredicates(hd, "P", "C", "X", existingRules, hd_ctypes)); if (hiter.hasNext()) sb.append(" |\n"); } sb.append(" }\n"); return sb; } private static StringBuilder createStepPredicates(HierarchyDefinition hd, String pVar, String cVar, String bVar, Map<TopicIF,StringBuilder> existingRules, Map<TopicIF,Set<HierarchyDefinition>> hd_ctypes) { StringBuilder sb = new StringBuilder(); if (hd.ptypes.size() > 1) sb.append("{"); Iterator<TopicIF> piter = hd.ptypes.iterator(); while (piter.hasNext()) { TopicIF ptype = piter.next(); sb.append(createHierarchyRuleFor(ptype, pVar, cVar, bVar, existingRules, hd_ctypes)); if (piter.hasNext()) sb.append(" | \n"); } if (hd.ptypes.size() > 1) sb.append("}"); return sb; } public static TreeModel createInstancesTreeModel2(TopicType topicType, boolean isAdminEnabled) { if (topicType == null) return new DefaultTreeModel(new DefaultMutableTreeNode("<root>")); TopicIF tt = topicType.getTopicIF(); String query = "using on for i\"http://psi.ontopia.net/ontology/\" " + "using hierarchy for i\"http://www.techquila.com/psi/hierarchy/#\" " + "hierarchical-parent($P, $C) :- " + "on:forms-hierarchy-for($TTYPE : on:topic-type, $ATYPE : on:association-type), " + "on:has-association-type($ATYPE : on:association-type, $AF : on:association-field), " + "on:has-association-field($AF : on:association-field, $RF1 : on:role-field), " + "on:has-role-type($RF1 : on:role-field, $PRT : on:role-type), " + "instance-of($PRT, hierarchy:superordinate-role-type), " + "on:has-association-field($AF : on:association-field, $RF2 : on:role-field), " + "on:has-role-type($RF2 : on:role-field, $CRT : on:role-type), " + "instance-of($CRT, hierarchy:subordinate-role-type), " + "type($A, $ATYPE), " + "association-role($A, $PR), type($PR, $PRT), " + "association-role($A, $CR), type($CR, $CRT), $PR /= $CR, " + "role-player($PR, $P), role-player($CR, $C). " + "select $P, $C from " + " instance-of($C, %topicType%), " + (!isAdminEnabled ? "not(direct-instance-of($C, on:system-topic)), " : "" ) + " { hierarchical-parent($P, $C) " + (!isAdminEnabled ? ", not(direct-instance-of($P, on:system-topic))" : "" ) + "} " + "order by $P, $C?"; Map<String,TopicIF> params = Collections.singletonMap("topicType", tt); // System.out.println("TT: " + tt); // System.out.println("HQ: " + query); final String topicMapId = topicType.getTopicMap().getId(); return new QueryTreeModel(topicType.getTopicMap(), query, params) { @Override protected DefaultMutableTreeNode createTreeNode(Object o) { return new DefaultMutableTreeNode(new TopicNode(topicMapId, ((TopicIF)o).getObjectId())); } }; } public static TreeModel createQueryTreeModel(TopicMap topicMap, String query, Map<String,?> params) { final String topicMapId = topicMap.getId(); return new QueryTreeModel(topicMap, query, params) { @Override protected DefaultMutableTreeNode createTreeNode(Object o) { return new DefaultMutableTreeNode(new TopicNode(topicMapId, ((TopicIF)o).getObjectId())); } }; } }