/* * #! * 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.query.impl.rdbms; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import net.ontopia.persistence.query.jdo.JDOBoolean; import net.ontopia.persistence.query.jdo.JDOCollection; import net.ontopia.persistence.query.jdo.JDOContains; import net.ontopia.persistence.query.jdo.JDOEquals; import net.ontopia.persistence.query.jdo.JDOField; import net.ontopia.persistence.query.jdo.JDOObject; import net.ontopia.persistence.query.jdo.JDOValueIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.impl.rdbms.Topic; import net.ontopia.topicmaps.query.core.InvalidQueryException; import net.ontopia.topicmaps.utils.TypeHierarchyUtils; import net.ontopia.utils.CompactHashSet; /** * INTERNAL: Implements the 'instance-of' predicate. */ public class InstanceOfPredicate extends net.ontopia.topicmaps.query.impl.basic.InstanceOfPredicate implements JDOPredicateIF { public InstanceOfPredicate(TopicMapIF topicmap) { super(topicmap); } // --- JDOPredicateIF implementation public boolean isRecursive() { return false; } public void prescan(QueryBuilder builder, List arguments) { } public boolean buildQuery(QueryBuilder builder, List expressions, List arguments) throws InvalidQueryException { // TODO: 'instance-of' does not yet support JDO expressions. // Interpret arguments Object[] args = arguments.toArray(); if (!(args[0] instanceof TopicIF || args[1] instanceof TopicIF)) { // instance-of(<any>, <any>) // NOTE: We cannot yet process this query if neither of the arguments are topics. return false; } else if (args[0] instanceof TopicIF && args[1] instanceof TopicIF) { // instance-of(topic, topic) TopicIF instance = (TopicIF)args[0]; TopicIF type = (TopicIF)args[1]; // Get all the instance types Collection itypes = getSuperclasses(instance.getTypes()); // Get all the type types TypeHierarchyUtils tu = new TypeHierarchyUtils(); Collection ttypes = new CompactHashSet(tu.getSubclasses(type)); ttypes.add(type); // TODO: this code can be optimized // Check to see if there is an overlap Iterator iter = itypes.iterator(); boolean overlap = false; while (iter.hasNext()) { if (ttypes.contains(iter.next())) overlap = true; } if (!overlap) expressions.add(JDOBoolean.FALSE); } else if (args[0] instanceof TopicIF) { // instance-of(topic, <any>) TopicIF instance = (TopicIF)args[0]; JDOValueIF jv_type = builder.createJDOValue(args[1]); // Get all the supertypes [including the direct types] Collection types = getSuperclasses(instance.getTypes()); if (types.isEmpty()) { expressions.add(JDOBoolean.FALSE); } else { // JDOQL: INSTANCE_TYPES.containsAll(TYPES) expressions.add(new JDOContains(new JDOCollection(types, Topic.class), jv_type)); } // JDOQL: INSTANCE.topicmap = TOPICMAP expressions.add(new JDOEquals(new JDOField(jv_type, "topicmap"), new JDOObject(topicmap))); } else if (args[1] instanceof TopicIF) { // instance-of(<any>, topic) JDOValueIF jv_instance = builder.createJDOValue(args[0]); TopicIF type = (TopicIF)args[1]; // Get all the subtypes TypeHierarchyUtils tu = new TypeHierarchyUtils(); Collection types = tu.getSubclasses(type); if (types.isEmpty()) { // JDOQL: INSTANCE.types.contains(TYPE) JDOValueIF jv_type = builder.createJDOValue(type); expressions.add(new JDOContains(new JDOField(jv_instance, "types"), jv_type)); } else { // JDOQL: TYPES.containsAll(INSTANCE_TYPES) types = new CompactHashSet(types); types.add(type); // JDOQL: INSTANCE_TYPES.containsAll(TYPES) // Note: that this is really a M:M comparison //! // With set pooling //! JDOVariable jv_types_var = builder.createJDOVariable("TYPES", TopicSet.class); //! JDOVariable jv_type_var = builder.createJDOVariable("TYPE", Topic.class); //! expressions.add(new JDOAnd(new JDOEquals(jv_types_var, new JDOField(jv_instance, "types")), //! new JDOContains(jv_types_var, jv_type_var), //! new JDOContains(new JDOCollection(types, Topic.class), jv_type_var))); // Without set pooling expressions.add(new JDOContains(new JDOCollection(types, Topic.class), new JDOField(jv_instance, "types"))); } // JDOQL: INSTANCE.topicmap = TOPICMAP expressions.add(new JDOEquals(new JDOField(jv_instance, "topicmap"), new JDOObject(topicmap))); } return true; } protected Collection getSuperclasses(Collection types) { if (types.isEmpty()) return Collections.EMPTY_SET; else { TypeHierarchyUtils tu = new TypeHierarchyUtils(); Collection result = new CompactHashSet(types); Iterator iter = types.iterator(); while (iter.hasNext()) { result.addAll(tu.getSuperclasses((TopicIF)iter.next())); } return result; } } }