/* * #! * 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.utils; import java.util.HashMap; import java.util.Map; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.impl.utils.Argument; import net.ontopia.topicmaps.impl.utils.ArgumentValidator; import net.ontopia.topicmaps.query.core.InvalidQueryException; import net.ontopia.topicmaps.query.impl.basic.QueryMatches; import net.ontopia.topicmaps.query.parser.Pair; import net.ontopia.topicmaps.query.parser.Parameter; import net.ontopia.topicmaps.query.parser.PredicateIF; import net.ontopia.topicmaps.query.parser.Variable; public class PredicateSignature extends ArgumentValidator { private static Map cache = new HashMap(); // used to avoid having to reparse public static PredicateSignature getSignature(PredicateIF predicate) throws InvalidQueryException { String sign = predicate.getSignature(); PredicateSignature signature = (PredicateSignature) cache.get(sign); if (signature == null) { signature = new PredicateSignature(sign); cache.put(sign, signature); } return signature; } private PredicateSignature(String signature) { super(signature); } public void interpretCharacter(char ch, Argument curarg) { if (ch == 'p') curarg.addType(Pair.class); else if (ch == 'z') curarg.addType(PredicateOptions.class); else super.interpretCharacter(ch, curarg); } /** * Validates the arguments to this predicate. If strict the types of * arguments are also checked. */ public void validateArguments(Object[] args, String predicate, boolean strict) throws InvalidQueryException { if (args.length == 0 && arguments.size() == 0) return; // special case int arg = 0; boolean repeated = false; for (int ix = 0; ix < args.length; ix++) { Argument curarg = getArgument(arg); if (curarg == null) throw new InvalidQueryException("Too many arguments to predicate " + predicate + ", got " + (ix+1) + ", wanted " + arg); if (!(args[ix] instanceof Pair) && curarg.requires(Pair.class)) throw new InvalidQueryException("Predicate " + predicate + " requires " + "pair as argument, got " + args[ix]); if (args[ix] instanceof Pair && curarg.allows(Pair.class)) { // the first member of the pair must be a topic Object value = ((Pair) args[ix]).getFirst(); if (strict && !(value instanceof Variable || value instanceof TopicIF || value instanceof Parameter)) throw new InvalidQueryException("First member of pair argument to " + predicate + " was not a topic"); } if (strict && !(args[ix] instanceof Variable || args[ix] instanceof Parameter) && !curarg.allows(args[ix].getClass())) throw new InvalidQueryException("Predicate " + predicate + " received " + getClassName(args[ix]) + " as argument " + (ix+1) + ", but requires " + getClassList(curarg.getTypes())); if (!curarg.isRepeatable()) arg++; else repeated = true; } Argument curarg = getArgument(arg); if (curarg != null && !curarg.isOptional() && !repeated) throw new InvalidQueryException("Not enough arguments to predicate " + predicate); } /** * INTERNAL: Verifies that arguments which are required to be bound * actually are bound. */ public void verifyBound(QueryMatches matches, Object[] arguments, PredicateIF predicate) throws InvalidQueryException { Argument lastArg = null; for (int ix = 0; ix < arguments.length; ix++) { Argument arg = getArgument(ix); // NOTE: arg can be null if last argument is repeatable if ((arg != null && arg.mustBeBound()) || (arg == null && lastArg != null && lastArg.isRepeatable() && lastArg.mustBeBound())) { int pos = matches.getIndex(arguments[ix]); if (!matches.bound(pos)) throw new InvalidQueryException("Variable " + matches.columnDefinitions[pos] + " not bound in predicate " + predicate.getName()); } if (arg != null) lastArg = arg; } } }