/*
* #!
* 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.basic;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import net.ontopia.topicmaps.core.DataTypes;
import net.ontopia.topicmaps.core.TopicNameIF;
import net.ontopia.topicmaps.core.OccurrenceIF;
import net.ontopia.topicmaps.core.TMObjectIF;
import net.ontopia.topicmaps.core.TopicIF;
import net.ontopia.topicmaps.core.TopicMapIF;
import net.ontopia.topicmaps.core.VariantNameIF;
import net.ontopia.topicmaps.core.index.NameIndexIF;
import net.ontopia.topicmaps.core.index.OccurrenceIndexIF;
import net.ontopia.topicmaps.query.core.InvalidQueryException;
import net.ontopia.topicmaps.query.impl.utils.Prefetcher;
import net.ontopia.topicmaps.query.parser.Variable;
import net.ontopia.topicmaps.query.impl.utils.PredicateDrivenCostEstimator;
import net.ontopia.utils.ObjectUtils;
/**
* INTERNAL: Implements the 'value' predicate.
*/
public class ValuePredicate implements BasicPredicateIF {
protected TopicMapIF topicmap;
protected NameIndexIF nameindex;
protected OccurrenceIndexIF occindex;
public ValuePredicate(TopicMapIF topicmap) {
this.topicmap = topicmap;
this.nameindex = (NameIndexIF) topicmap
.getIndex("net.ontopia.topicmaps.core.index.NameIndexIF");
this.occindex = (OccurrenceIndexIF) topicmap
.getIndex("net.ontopia.topicmaps.core.index.OccurrenceIndexIF");
}
public String getName() {
return "value";
}
public String getSignature() {
return "bov s";
}
public int getCost(boolean[] boundparams) {
if (boundparams[0] && boundparams[1])
return PredicateDrivenCostEstimator.FILTER_RESULT;
else if (boundparams[0] && !boundparams[1])
return PredicateDrivenCostEstimator.SINGLE_RESULT;
else if (!boundparams[0] && boundparams[1])
return PredicateDrivenCostEstimator.SMALL_RESULT;
else
return PredicateDrivenCostEstimator.WHOLE_TM_RESULT;
}
public QueryMatches satisfy(QueryMatches matches, Object[] arguments)
throws InvalidQueryException {
int objix = matches.getIndex(arguments[0]);
int valueix = matches.getIndex(arguments[1]);
if (matches.bound(objix) && !matches.bound(valueix)) {
prefetchValue(matches, arguments, objix);
return PredicateUtils.objectToOne(matches, objix, valueix,
TMObjectIF.class,
PredicateUtils.OBJECT_TO_VALUE);
} else if (!matches.bound(objix) && matches.bound(valueix)) {
return lookupObjects(matches, objix, valueix);
} else if (matches.bound(objix) && matches.bound(valueix)) {
prefetchValue(matches, arguments, objix);
return PredicateUtils.filter(matches, objix, valueix,
TMObjectIF.class, String.class,
PredicateUtils.FILTER_VALUE);
} else {
prefetchValue(matches, arguments, objix);
return PredicateUtils.collectionToOne(matches, getObjects(), objix, valueix,
PredicateUtils.GENERATE_VALUE);
}
}
protected void prefetchValue(QueryMatches matches, Object[] arguments, int objix) {
if (arguments[0] instanceof Variable) {
String varname = ((Variable)arguments[0]).getName();
Object[] types = matches.getQueryContext().getVariableTypes(varname);
if (types != null) {
for (int i=0; i < types.length; i++) {
if (TopicNameIF.class.equals(types[i])) {
Prefetcher.prefetch(topicmap, matches, objix,
Prefetcher.TopicNameIF,
Prefetcher.TopicNameIF_value, false);
} else if (OccurrenceIF.class.equals(types[i])) {
Prefetcher.prefetch(topicmap, matches, objix,
Prefetcher.OccurrenceIF,
Prefetcher.OccurrenceIF_value, false);
} else if (VariantNameIF.class.equals(types[i])) {
Prefetcher.prefetch(topicmap, matches, objix,
Prefetcher.VariantNameIF,
Prefetcher.VariantNameIF_value, false);
}
}
}
}
}
private QueryMatches lookupObjects(QueryMatches matches,
int objix, int valueix) {
int objtypes = getObjectTypes(matches, objix);
QueryMatches result = new QueryMatches(matches);
for (int ix = 0; ix <= matches.last; ix++) {
if (!(matches.data[ix][valueix] instanceof String))
continue;
String value = (String) matches.data[ix][valueix];
Collection objects = new ArrayList();
if ((objtypes & NAME_TYPE) != 0) {
objects.addAll(nameindex.getTopicNames(value));
objects.addAll(filterVariants(nameindex.getVariants(value)));
}
if ((objtypes & OCC_TYPE) != 0)
objects.addAll(filterOccurrences(occindex.getOccurrences(value)));
if (objects.isEmpty())
continue;
while (result.last + objects.size() >= result.size)
result.increaseCapacity();
Object[] values = objects.toArray();
for (int pos = 0; pos < values.length; pos++) {
Object[] newRow = (Object[]) matches.data[ix].clone();
newRow[objix] = values[pos];
result.data[++result.last] = newRow;
}
}
return result;
}
// --- Helpers
// used to see what types the object parameter may have
private static final int NO_TYPES = 0;
private static final int NAME_TYPE = 1;
private static final int OCC_TYPE = 2;
private static final int ALL_TYPES = 3;
private int getObjectTypes(QueryMatches matches, int objix) {
QueryContext context = matches.getQueryContext();
String varname = ((Variable) matches.getColumnDefinition(objix)).getName();
Object[] vartypes = context.getVariableTypes(varname);
if (vartypes == null)
return ALL_TYPES;
int types = NO_TYPES;
for (int ix = 0; ix < vartypes.length; ix++) {
if (vartypes[ix].equals(TopicNameIF.class) ||
vartypes[ix].equals(VariantNameIF.class))
types |= NAME_TYPE;
else if (vartypes[ix].equals(OccurrenceIF.class))
types |= OCC_TYPE;
}
return types;
}
protected Object[] getObjects() {
TopicIF[] topics = (TopicIF[]) topicmap.getTopics().toArray(new TopicIF[] {});
Collection objects = new ArrayList(topics.length * 3);
for (int tix = 0; tix < topics.length; tix++) {
Collection bns = topics[tix].getTopicNames();
objects.addAll(bns);
objects.addAll(filterOccurrences(topics[tix].getOccurrences()));
Iterator it = bns.iterator();
while (it.hasNext()) {
TopicNameIF bn = (TopicNameIF) it.next();
objects.addAll(filterVariants(bn.getVariants()));
}
}
return objects.toArray();
}
private static Collection filterOccurrences(Collection occs) {
Collection result = new ArrayList(occs.size());
Iterator iter = occs.iterator();
while (iter.hasNext()) {
OccurrenceIF occ = (OccurrenceIF) iter.next();
if (ObjectUtils.different(occ.getDataType(), DataTypes.TYPE_URI))
result.add(occ);
}
return result;
}
private static Collection filterVariants(Collection vns) {
Collection result = new ArrayList(vns.size());
Iterator iter = vns.iterator();
while (iter.hasNext()) {
VariantNameIF vn = (VariantNameIF) iter.next();
if (ObjectUtils.different(vn.getDataType(), DataTypes.TYPE_URI))
result.add(vn);
}
return result;
}
}