/* * #! * 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.impl.utils; import java.util.Map; import java.util.List; import java.util.HashMap; import java.util.ArrayList; import net.ontopia.infoset.core.LocatorIF; import net.ontopia.topicmaps.core.AssociationIF; import net.ontopia.topicmaps.core.AssociationRoleIF; import net.ontopia.topicmaps.core.TopicNameIF; import net.ontopia.topicmaps.core.OccurrenceIF; import net.ontopia.topicmaps.core.TopicIF; import net.ontopia.topicmaps.core.TopicMapIF; import net.ontopia.topicmaps.core.VariantNameIF; import net.ontopia.topicmaps.query.parser.Pair; import net.ontopia.utils.OntopiaRuntimeException; /** * INTERNAL: Instances of this class represent a signature of some * predicate/function/object that takes a positional list of arguments * and can validate whether a given list of arguments are valid * according to the signature. */ public class ArgumentValidator { protected List<Argument> arguments; /** * INTERNAL: Creates a validator for the signature represented by * this string. */ public ArgumentValidator(String signature) { arguments = new ArrayList<Argument>(); if (signature.length() == 0) return; // otherwise we'll add an empty argument... Argument curarg = new Argument(); for (int ix = 0; ix < signature.length(); ix++) { if (signature.charAt(ix) == ' ') { arguments.add(curarg); curarg = new Argument(); } else interpretCharacter(signature.charAt(ix), curarg); } arguments.add(curarg); } /** * INTERNAL: Interprets the given character and updates the argument * to record the information in the character. * * <pre> * x TMObjectIF (equivalent to mtarbvo) * m TopicMapIF * t TopicIF * a AssociationIF * r AssociationRoleIF * b TopicNameIF * v VariantNameIF * o OccurrenceIF * l LocatorIF * * p Pair (tolog-specific) * B Boolean * s String * n Number (float + integer) * i Integer * f Float * . Object * z PredicateOptions (tolog-specific wizardry) * * ? optional argument * + repeatable argument * & multiple values * ! tolog: argument must be bound; webed: argument must have a value * </pre> */ public void interpretCharacter(char ch, Argument curarg) { switch(ch) { case 'm': curarg.addType(TopicMapIF.class); break; case 't': curarg.addType(TopicIF.class); break; case 'a': curarg.addType(AssociationIF.class); break; case 'r': curarg.addType(AssociationRoleIF.class); break; case 'b': curarg.addType(TopicNameIF.class); break; case 'v': curarg.addType(VariantNameIF.class); break; case 'o': curarg.addType(OccurrenceIF.class); break; case 'l': curarg.addType(LocatorIF.class); break; case 's': curarg.addType(String.class); break; case 'n': curarg.addType(Integer.class); curarg.addType(Float.class); break; case 'i': curarg.addType(Integer.class); break; case 'f': curarg.addType(Float.class); break; case 'B': curarg.addType(Boolean.class); break; case '.': curarg.addType(Object.class); break; case 'x': curarg.addType(TopicMapIF.class); curarg.addType(TopicIF.class); curarg.addType(TopicNameIF.class); curarg.addType(VariantNameIF.class); curarg.addType(OccurrenceIF.class); curarg.addType(AssociationIF.class); curarg.addType(AssociationRoleIF.class); break; case '?': curarg.setOptional(); break; case '+': curarg.setRepeatable(); break; case '!': curarg.setMustBeBound(); break; case '&': curarg.setMultiValue(); break; default: throw new OntopiaRuntimeException("INTERNAL ERROR: Unknown type signature " + "character '" + ch + "' passed to " + getClass().getName()); } } public Class[] getTypes(int ix) { if (ix >= arguments.size()) ix = arguments.size() - 1; Argument arg = arguments.get(ix); return arg.getTypes(); } /** * INTERNAL: Returns an Argument object representing the argument at * this position in the signature. */ public Argument getArgument(int ix) { if (ix >= arguments.size()) return null; else return arguments.get(ix); } /** * INTERNAL: Turns a list of class types into a signature string. * @param types The list of class types. * @return The generated signature string. */ public static String makeSignature(Object[] types) { char[] sign = new char[types.length]; for (int ix = 0; ix < types.length; ix++) { Class type = (Class) types[ix]; if (type.equals(TopicMapIF.class)) sign[ix] = 'm'; else if (type.equals(TopicIF.class)) sign[ix] = 't'; else if (type.equals(TopicNameIF.class)) sign[ix] = 'b'; else if (type.equals(VariantNameIF.class)) sign[ix] = 'v'; else if (type.equals(OccurrenceIF.class)) sign[ix] = 'o'; else if (type.equals(AssociationIF.class)) sign[ix] = 'a'; else if (type.equals(AssociationRoleIF.class)) sign[ix] = 'r'; else if (type.equals(LocatorIF.class)) sign[ix] = 'l'; else if (type.equals(String.class)) sign[ix] = 's'; else if (type.equals(Number.class)) sign[ix] = 'n'; else if (type.equals(Integer.class)) sign[ix] = 'i'; else if (type.equals(Float.class)) sign[ix] = 'f'; else if (type.equals(Object.class)) sign[ix] = '.'; else if (type.equals(Pair.class)) sign[ix] = 'p'; else throw new OntopiaRuntimeException("INTERNAL ERROR: Unknown type " + type); } return new String(sign); } // --- ERROR MESSAGE METHODS /** * INTERNAL: Returns a string name for the class. */ public static String getClassName(Class klass) { String classname = typenames.get(klass); if (classname == null) classname = klass.toString(); return classname; } /** * INTERNAL: Returns a string name for the class of this object. */ public static String getClassName(Object object) { return getClassName(object.getClass()); } /** * INTERNAL: Returns a nicely formatted list of class names. */ public static String getClassList(Object[] classes) { StringBuilder buf = new StringBuilder(); for (int ix = 0; ix < classes.length; ix++) { buf.append(getClassName((Class) classes[ix])); if (ix + 2 < classes.length) buf.append(", "); else if (ix + 1 < classes.length) buf.append(", or "); } return buf.toString(); } // --- TYPE MAP // used to get nice type names in error messages protected static Map<Class<?>, String> typenames; static { typenames = new HashMap<Class<?>, String>(); typenames.put(net.ontopia.topicmaps.core.AssociationIF.class, "an association"); typenames.put(net.ontopia.topicmaps.core.TopicIF.class, "a topic"); typenames.put(net.ontopia.topicmaps.core.TopicMapIF.class, "a topic map"); typenames.put(net.ontopia.topicmaps.core.TopicNameIF.class, "a base name"); typenames.put(net.ontopia.topicmaps.core.VariantNameIF.class, "a variant name"); typenames.put(net.ontopia.topicmaps.core.OccurrenceIF.class, "an occurrence"); typenames.put(net.ontopia.topicmaps.core.AssociationRoleIF.class, "an association role"); typenames.put(net.ontopia.topicmaps.impl.basic.Association.class, "an association"); typenames.put(net.ontopia.topicmaps.impl.basic.Topic.class, "a topic"); typenames.put(net.ontopia.topicmaps.impl.basic.TopicMap.class, "a topic map"); typenames.put(net.ontopia.topicmaps.impl.basic.TopicName.class, "a base name"); typenames.put(net.ontopia.topicmaps.impl.basic.VariantName.class, "a variant name"); typenames.put(net.ontopia.topicmaps.impl.basic.Occurrence.class, "an occurrence"); typenames.put(net.ontopia.topicmaps.impl.basic.AssociationRole.class, "an association role"); typenames.put(String.class, "a string"); // add RDBMS classes if we have them try { typenames.put(net.ontopia.topicmaps.impl.rdbms.Association.class, "an association"); typenames.put(net.ontopia.topicmaps.impl.rdbms.Topic.class, "a topic"); typenames.put(net.ontopia.topicmaps.impl.rdbms.TopicMap.class, "a topic map"); typenames.put(net.ontopia.topicmaps.impl.rdbms.TopicName.class, "a base name"); typenames.put(net.ontopia.topicmaps.impl.rdbms.VariantName.class, "a variant name"); typenames.put(net.ontopia.topicmaps.impl.rdbms.Occurrence.class, "an occurrence"); typenames.put(net.ontopia.topicmaps.impl.rdbms.AssociationRole.class, "an association role"); } catch (NoClassDefFoundError e) { } } }