Parser.java revision 9a70fc3be3b1e966bf78825cdb8d509963a6f0a1
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2001,2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*/
// Parser.java: LDAP Parser for those service stores that need it.
// Author: James Kempf
// Created On: Mon Apr 27 08:11:08 1998
// Last Modified By: James Kempf
// Last Modified On: Mon Mar 1 08:29:36 1999
// Update Count: 45
//
/**
* The Parser class implements LDAP query parsing for ServiceStoreInMemory.
* It is an internal class because it must know about the internal
* structure of the hashtables.
*
* @author James Kempf
*/
final private static char NONASCII_LOWER = '\u0080';
final private static char NONASCII_UPPER = '\uffff';
final static char EQUAL = '=';
final static char LESS = '<';
final static char GREATER = '>';
private final static char STAR = '*';
private final static char OPAREN = '(';
private final static char CPAREN = ')';
private final static char APPROX = '~';
private final static char NOT = '!';
private final static char AND = '&';
private final static char OR = '|';
private final static char SPACE = ' ';
/**
* Record for returning stuff to the service store.
*
* @author James Kempf
*/
static final class ParserRecord extends Object {
}
/**
* The QueryEvaluator interface evaluates a term in a query, given
* the attribute id, the operator, the object, and whether the
* term is currently under negation from a not operator. Only those
* ServiceStore implemenations that want to use the Parser
* class to perform query parsing must provide this.
*
* @author James Kempf
*/
interface QueryEvaluator {
/**
* Evaluate the query, storing away the services that match.
*
* @param tag The attribute tag for the term.
* @param op The term operator.
* @param pattern the operand of the term.
* @param invert True if the results of the comparison should be
* inverted due to a not operator.
* @param returns Hashtable for the returns. The returns are
* structured exactly like the hashtable
* returned from findServices().
* @return True if the term matched, false if not.
*/
char op,
boolean invert,
throws ServiceLocationException;
}
/**
* Parse a query and incrementally evaluate.
*
* @param urlLevel Hashtable of langlevel hashtables containing
* registrations for the service type and scope.
* @param query The query. Escapes have not yet been processed.
* @param ret Vector for returned records.
* @param locale Locale in which to interpret query strings.
* @param ret ParserRecord in which to return the results.
*/
static void
throws ServiceLocationException {
// Create and initialize lexical analyzer.
// Begin parsing.
try {
// Throw exception if anything occurs after the
// parsed expression.
throw
"par_char_closing",
}
// Merge in returns. Use OR operator so all returned
// values are merged in.
} catch (IOException ex) {
throw
"par_syn_err",
}
}
//
// Routines for dealing with parse returns record.
//
// Merge source to target. The target has already
// been precharged with ones that must match
// if the op is AND. If it's OR, then simply
// stuff them in.
private static boolean
char op) {
boolean eval;
} else {
}
} else {
}
return eval;
}
// Merge tables by removing anything from target that isn't in source.
// Remove any from target that aren't in source.
while (en.hasMoreElements()) {
}
}
// If there's nothing left, return false to indicate no further
// evaluation needed.
return false;
}
return true;
}
// Merge tables by adding everything from source into target.
while (en.hasMoreElements()) {
}
return true;
}
//
// Parsing for various productions.
//
// Parse the filter production.
private static ParserRecord
boolean invert,
boolean eval)
throws ServiceLocationException, IOException {
// Check for opening paren.
throw
"par_init_par",
new Object[0]);
}
// Parse inside.
// Check for a logical operator.
} else {
// Since we've covered the ASCII character set, the only other
// thing that could be here is a nonASCII character. We push it
// back and deal with it in parseItem().
}
// Check for closing paren.
throw
"par_final_par",
new Object[0]);
}
return ret;
}
// Parse a filterlist production.
private static ParserRecord
char op,
boolean invert,
boolean eval)
throws ServiceLocationException, IOException {
boolean match;
// Parse through the list of filters.
do {
} else {
}
// We need to start off with something.
} else {
// Merge in returns.
}
// Look for ending paren.
return mrex;
}
} while (true);
}
// Parse item.
private static ParserRecord
boolean invert,
boolean eval)
throws ServiceLocationException, IOException {
// If operator is PRESENT, then check whether
// it's not really a wildcarded value. If the next
// token isn't a closing paren, then it's
// a wildcarded value.
// Need to convert to a wildcarded pattern. Regardless
// of type, since wildcard makes the type be a
// string.
value =
}
} else {
}
// Check for inappropriate pattern.
if (value instanceof AttributePattern &&
throw
"par_wild_op",
}
// Check for inappropriate boolean.
throw
"par_bool_op",
}
// Check for wrong operator with keyword.
throw
"par_key_op",
}
if (eval) {
/*
* Try and evaluate the query. If the evaluation failed and the
* value was an Integer or Boolean try again after converting the
* value to a String. This is because the value in the query will
* be converted to an Integer or Boolean in preference to a String
* even though the query starts out as a String. Hence when an
* attribute is registered with a String value that can equally be
* parsed as a valid Integer or Boolean value the String will
* almost always be parsed as an Integer or Boolean. This results
* in the failing of the initial type check when performing the
* query. By converting the value to a String there is another shot
* at fulfulling the query.
*/
!(value instanceof AttributeString)) {
op,
new AttributeString(
locale),
prex);
}
}
return prex;
}
// Parse attribute tag.
throws ServiceLocationException, IOException {
str =
}
// Parse attribute operator.
throws ServiceLocationException, IOException {
// Identify operator
switch (tok) {
case EQUAL:
// Is it present?
return PRESENT;
} else {
return EQUAL;
}
// Need equals.
break;
}
}
return (char)tok;
default:
break;
}
throw
"par_comp_op",
new Object[0]);
}
// Parse expression value.
throws ServiceLocationException, IOException {
// Parse until the next closing paren.
do {
Object o =
if (o instanceof String) {
} else if (o instanceof byte[]) {
o = new Opaque((byte[])o);
}
return o;
"par_ntok",
new Object[0]);
} else {
}
} else {
throw
"par_qend",
new Object[0]);
}
} while (true);
}
// NonASCII characters may be in the string. StreamTokenizer
// can't handle them as part of words, so we need to resort to
// this loop to handle it.
throws IOException {
do {
} else if (((char)tok >= NONASCII_LOWER) &&
((char)tok <= NONASCII_UPPER)) {
} else {
break;
}
} while (true);
}
}