blob: 336d46d9f3ae6ae9ac67efd2669903392a17393f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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
*
* https://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 org.apache.ivy.osgi.filter;
import java.text.ParseException;
import org.apache.ivy.osgi.filter.CompareFilter.Operator;
public class OSGiFilterParser {
public static OSGiFilter parse(String text) throws ParseException {
return new Parser(text).parse();
}
static class Parser {
/**
* text to parse
*/
private final String text;
/**
* the length of the source
*/
private int length;
/**
* position in the source
*/
private int pos = 0;
/**
* last read character
*/
private char c;
/**
* Default constructor
*
* @param text
* the header to parse
*/
Parser(String text) {
this.text = text;
this.length = text.length();
}
/**
* Do the parsing
*
* @return OSGiFilter
*
* @throws ParseException if something goes wrong
*/
OSGiFilter parse() throws ParseException {
return parseFilter();
}
private char readNext() {
if (pos == length) {
c = '\0';
} else {
c = text.charAt(pos++);
}
return c;
}
private void unread() {
if (pos > 0) {
pos--;
}
}
private OSGiFilter parseFilter() throws ParseException {
skipWhiteSpace();
readNext();
if (c != '(') {
throw new ParseException("Expecting '(' as the start of the filter", pos);
}
OSGiFilter filter = parseFilterComp();
readNext();
if (c != ')') {
throw new ParseException("Expecting ')' as the end of the filter", pos);
}
return filter;
}
private OSGiFilter parseFilterComp() throws ParseException {
OSGiFilter filter;
switch (readNext()) {
case '&':
filter = parseAnd();
break;
case '|':
filter = parseOr();
break;
case '!':
filter = parseNot();
break;
default:
unread();
filter = parseOperation();
break;
}
return filter;
}
private OSGiFilter parseOperation() throws ParseException {
String leftValue = parseCompareValue();
Operator operator = parseCompareOperator();
String rightValue = parseCompareValue();
return new CompareFilter(leftValue, operator, rightValue);
}
private String parseCompareValue() {
StringBuilder builder = new StringBuilder();
do {
readNext();
if (!isOperator(c) && c != ')' && c != '(') {
builder.append(c);
} else {
unread();
break;
}
} while (pos < length);
return builder.toString();
}
private boolean isOperator(char ch) {
return ch == '=' || ch == '<' || ch == '>' || ch == '~';
}
private Operator parseCompareOperator() throws ParseException {
switch (readNext()) {
case '=':
if (readNext() == '*') {
return Operator.PRESENT;
}
unread();
return Operator.EQUALS;
case '>':
if (readNext() == '=') {
return Operator.GREATER_OR_EQUAL;
}
unread();
return Operator.GREATER_THAN;
case '<':
if (readNext() == '=') {
return Operator.LOWER_OR_EQUAL;
}
unread();
return Operator.LOWER_THAN;
case '~':
if (readNext() == '=') {
return Operator.LOWER_OR_EQUAL;
}
unread();
default:
break;
}
throw new ParseException("Expecting an operator: =, <, <=, >, >=, ~= or =*", pos);
}
private OSGiFilter parseAnd() throws ParseException {
AndFilter filter = new AndFilter();
parseFilterList(filter);
return filter;
}
private OSGiFilter parseOr() throws ParseException {
OrFilter filter = new OrFilter();
parseFilterList(filter);
return filter;
}
private void parseFilterList(MultiOperatorFilter filter) throws ParseException {
do {
skipWhiteSpace();
readNext();
if (c == '(') {
unread();
filter.add(parseFilter());
} else {
unread();
break;
}
} while (pos < length);
if (filter.getSubFilters().size() == 0) {
throw new ParseException("Expecting at least one sub filter", pos);
}
}
private OSGiFilter parseNot() throws ParseException {
readNext();
if (c != '(') {
throw new ParseException("The ! operator is expecting a filter", pos);
}
unread();
return new NotFilter(parseFilter());
}
private void skipWhiteSpace() {
do {
switch (readNext()) {
case ' ':
continue;
default:
unread();
return;
}
} while (pos < length);
}
}
}