You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2015/11/17 16:04:11 UTC
[01/23] olingo-odata4 git commit: [OLINGO-568] SearchTokenizer for
SearchParser
Repository: olingo-odata4
Updated Branches:
refs/heads/master be3b10a24 -> ae1b2754b
[OLINGO-568] SearchTokenizer for SearchParser
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/452ebcbd
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/452ebcbd
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/452ebcbd
Branch: refs/heads/master
Commit: 452ebcbdd80d358b71e1e1eb2f8a9830e7aaa59f
Parents: ac828a3
Author: Michael Bolz <mi...@sap.com>
Authored: Fri Nov 6 15:42:32 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Fri Nov 6 15:43:36 2015 +0100
----------------------------------------------------------------------
.../olingo/server/core/uri/parser/Parser.java | 21 +-
.../core/uri/parser/search/SearchParser.java | 33 ++
.../uri/parser/search/SearchQueryToken.java | 26 ++
.../core/uri/parser/search/SearchTokenizer.java | 396 +++++++++++++++++++
.../core/uri/queryoption/SearchOptionImpl.java | 7 +-
.../uri/parser/search/SearchParserTest.java | 30 ++
.../uri/parser/search/SearchTokenizerTest.java | 388 ++++++++++++++++++
.../core/uri/antlr/TestFullResourcePath.java | 17 +-
8 files changed, 902 insertions(+), 16 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index 8732341..82094cf 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@ -55,6 +55,7 @@ import org.apache.olingo.server.core.uri.antlr.UriParserParser.MetadataEOFContex
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.PathSegmentEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectEOFContext;
+import org.apache.olingo.server.core.uri.parser.search.SearchParser;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
@@ -77,7 +78,7 @@ public class Parser {
int logLevel = 0;
private enum ParserEntryRules {
- All, Batch, CrossJoin, Entity, ExpandItems, FilterExpression, Metadata, PathSegment, Orderby, Select
+ All, Batch, CrossJoin, Entity, ExpandItems, FilterExpression, Metadata, PathSegment, Orderby, Select, Search
}
public Parser setLogLevel(final int logLevel) {
@@ -215,8 +216,8 @@ public class Parser {
systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
} else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
- throw new UriParserSemanticException("System query option '$search' not implemented!",
- UriParserSemanticException.MessageKeys.NOT_IMPLEMENTED, "System query option '$search");
+ SearchParser searchParser = new SearchParser();
+ systemOption = searchParser.parse(path, option.value);
} else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
SelectEOFContext ctxSelectEOF =
(SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
@@ -285,15 +286,15 @@ public class Parser {
parameter.setAlias(option.name);
parameter.setExpression(expression);
parameter.setText(NULL.equals(option.value) ? null : option.value);
-
+
if(context.contextUriInfo.getAlias(option.name) == null) {
context.contextUriInfo.addAlias(option.name, parameter);
} else {
- throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
+ throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
}
}
-
+
final CustomQueryOptionImpl customOption = new CustomQueryOptionImpl();
customOption.setName(option.name);
customOption.setText(option.value);
@@ -388,6 +389,9 @@ public class Parser {
case Select:
ret = parser.selectEOF();
break;
+ case Search:
+ ret = parser.searchInline();
+ break;
default:
break;
@@ -445,6 +449,9 @@ public class Parser {
case Select:
ret = parser.selectEOF();
break;
+ case Search:
+ ret = parser.searchInline();
+ break;
default:
break;
}
@@ -503,7 +510,7 @@ public class Parser {
} else {
out.append(index);
}
- out.append(nL);
+ out.append(nL);
}
out.append(']');
System.out.println("tokens: " + out.toString());
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
new file mode 100644
index 0000000..d508932
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -0,0 +1,33 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
+
+import java.util.List;
+
+public class SearchParser {
+
+ public SearchOption parse(String path, String value) {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> tokens = tokenizer.tokenize(value);
+ return new SearchOptionImpl();
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
new file mode 100644
index 0000000..a08c1a2
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
@@ -0,0 +1,26 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+public interface SearchQueryToken {
+ enum Token {OPEN, BWS, RWS, TERM, SEARCH_EXPRESSION, NOT, AND, OR, WORD, PHRASE, CLOSE}
+
+ Token getToken();
+ String getLiteral();
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
new file mode 100644
index 0000000..7d2b559
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -0,0 +1,396 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <code>
+ * searchExpr = ( OPEN BWS searchExpr BWS CLOSE
+ * / searchTerm
+ * ) [ searchOrExpr
+ * / searchAndExpr
+ * ]
+ *
+ * searchOrExpr = RWS 'OR' RWS searchExpr
+ * searchAndExpr = RWS [ 'AND' RWS ] searchExpr
+ *
+ * searchTerm = [ 'NOT' RWS ] ( searchPhrase / searchWord )
+ * searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
+ * searchWord = 1*ALPHA ; Actually: any character from the Unicode categories L or Nl,
+ * ; but not the words AND, OR, and NOT
+ * </code>
+ */
+public class SearchTokenizer {
+ //RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
+ //BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
+
+
+ private static abstract class State implements SearchQueryToken {
+ private Token token = null;
+ private boolean finished = false;
+ private final StringBuilder literal;
+
+ public static final char EOF = 0x03;
+
+ public State(Token t) {
+ token = t;
+ literal = new StringBuilder();
+ }
+ public State(Token t, char c) {
+ this(t);
+ init(c);
+ }
+ public State(Token t, State consumeState) {
+ token = t;
+ literal = new StringBuilder(consumeState.getLiteral());
+ }
+
+ protected abstract State nextChar(char c);
+
+ public State next(char c) {
+ return nextChar(c);
+ }
+
+ public State init(char c) {
+ if(isFinished()) {
+ throw new IllegalStateException(toString() + " is already finished.");
+ }
+ literal.append(c);
+ return this;
+ }
+
+ public State allowed(char c) {
+ literal.append(c);
+ return this;
+ }
+
+ public State forbidden(char c) {
+ throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ }
+
+ public State finish() {
+ this.finished = true;
+ return this;
+ }
+
+ public boolean isFinished() {
+ return finished;
+ }
+
+ public Token getToken() {
+ return token;
+ }
+
+ static boolean isAllowedChar(final char character) {
+ // TODO mibo: add missing allowed characters
+ return 'A' <= character && character <= 'Z' // case A..Z
+ || 'a' <= character && character <= 'z' // case a..z
+ || '0' <= character && character <= '9'; // case 0..9
+ }
+
+ /**
+ * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
+ * qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * @param character which is checked
+ * @return true if character is allowed for a phrase
+ */
+ static boolean isAllowedPhrase(final char character) {
+ // FIXME mibo: check missing and '\''
+ return isAllowedChar(character)
+ || character == '-'
+ || character == '.'
+ || character == '_'
+ || character == '~'
+ || character == ':'
+ || character == '@'
+ || character == '/'
+ || character == '$'
+ || character == '=';
+ }
+
+ static boolean isEof(final char character) {
+ return character == EOF;
+ }
+
+ static boolean isWhitespace(final char character) {
+ //( SP / HTAB / "%20" / "%09" )
+ // TODO mibo: add missing whitespaces
+ return character == ' ' || character == '\t';
+ }
+
+ @Override
+ public String getLiteral() {
+ return literal.toString();
+ }
+
+ @Override
+ public String toString() {
+ return this.getToken().toString() + "=>{" + literal.toString() + "}";
+ }
+ }
+
+ private class SearchExpressionState extends State {
+ public SearchExpressionState() {
+ super(Token.SEARCH_EXPRESSION);
+ }
+ @Override
+ public State nextChar(char c) {
+ if (c == '(') {
+ return new OpenState(c);
+ } else if (isWhitespace(c)) {
+ return new RwsState(c);
+ } else if(c == ')') {
+ return new CloseState(c);
+ } else if(isEof(c)) {
+ return finish();
+ } else {
+ return new SearchTermState().init(c);
+ }
+ }
+
+ @Override
+ public State init(char c) {
+ return nextChar(c);
+ }
+ }
+
+ private class SearchTermState extends State {
+ public SearchTermState() {
+ super(Token.TERM);
+ }
+ @Override
+ public State nextChar(char c) {
+ if(c == 'n' || c == 'N') {
+ return new NotState(c);
+ } else if (c == '\'') {
+ return new SearchPhraseState(c);
+ } else if (isAllowedChar(c)) {
+ return new SearchWordState(c);
+ } else if (c == ')') {
+ finish();
+ return new CloseState(c);
+ } else if (isWhitespace(c)) {
+ finish();
+ return new RwsState(c);
+ } else if (isEof(c)) {
+ return finish();
+ }
+ throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ }
+ @Override
+ public State init(char c) {
+ return nextChar(c);
+ }
+ }
+
+ private class SearchWordState extends State {
+ public SearchWordState(char c) {
+ super(Token.WORD, c);
+ }
+ public SearchWordState(State toConsume) {
+ super(Token.WORD, toConsume);
+ }
+
+ @Override
+ public State nextChar(char c) {
+ // if(c == 'n' || c == 'N') {
+ // return new NotState(c);
+ // }
+ if (isAllowedChar(c)) {
+ return allowed(c);
+ } else if (c == ')') {
+ finish();
+ return new CloseState(c);
+ } else if (isWhitespace(c)) {
+ finish();
+ return new RwsState(c);
+ } else if (isEof(c)) {
+ return finish();
+ }
+ throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ }
+ }
+
+ private class SearchPhraseState extends State {
+ public SearchPhraseState(char c) {
+ super(Token.PHRASE, c);
+ if(c != '\'') {
+ forbidden(c);
+ }
+ }
+
+ @Override
+ public State nextChar(char c) {
+ if(isFinished() && !isEof(c)) {
+ return new SearchExpressionState().init(c);
+ } else if (isAllowedPhrase(c)) {
+ return allowed(c);
+ } else if (c == '\'') {
+ finish();
+ return allowed(c);
+ } else if (isWhitespace(c)) {
+ if(isFinished()) {
+ return new RwsState(c);
+ }
+ return allowed(c);
+ } else if (isEof(c)) {
+ return finish();
+ }
+ throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ }
+ }
+
+ private class OpenState extends State {
+ public OpenState(char c) {
+ super(Token.OPEN, c);
+ finish();
+ }
+ @Override
+ public State nextChar(char c) {
+ finish();
+ if (isWhitespace(c)) {
+ throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ }
+ return new SearchExpressionState().init(c);
+ }
+ }
+
+ private class CloseState extends State {
+ public CloseState(char c) {
+ super(Token.CLOSE, c);
+ finish();
+ }
+
+ @Override
+ public State nextChar(char c) {
+ if (isEof(c)) {
+ return finish();
+ } else {
+ return new SearchExpressionState().init(c);
+ }
+ }
+ }
+
+ private class NotState extends State {
+ public NotState(char c) {
+ super(Token.NOT, c);
+ }
+ @Override
+ public State nextChar(char c) {
+ if (getLiteral().length() == 1 && (c == 'o' || c == 'O')) {
+ return allowed(c);
+ } else if (getLiteral().length() == 2 && (c == 't' || c == 'T')) {
+ return allowed(c);
+ } else if(getLiteral().length() == 3 && isWhitespace(c)) {
+ finish();
+ return new RwsState(c);
+ } else {
+ return new SearchWordState(this);
+ }
+ }
+ }
+
+ private class AndState extends State {
+ public AndState(char c) {
+ super(Token.AND, c);
+ if(c != 'a' && c != 'A') {
+ forbidden(c);
+ }
+ }
+ @Override
+ public State nextChar(char c) {
+ if (getLiteral().length() == 1 && (c == 'n' || c == 'N')) {
+ return allowed(c);
+ } else if (getLiteral().length() == 2 && (c == 'd' || c == 'D')) {
+ return allowed(c);
+ } else if(getLiteral().length() == 3 && isWhitespace(c)) {
+ finish();
+ return new RwsState(c);
+ } else {
+ return new SearchWordState(this);
+ }
+ }
+ }
+
+ private class OrState extends State {
+ public OrState(char c) {
+ super(Token.OR, c);
+ if(c != 'o' && c != 'O') {
+ forbidden(c);
+ }
+ }
+ @Override
+ public State nextChar(char c) {
+ if (getLiteral().length() == 1 && (c == 'r' || c == 'R')) {
+ return allowed(c);
+ } else if(getLiteral().length() == 2 && isWhitespace(c)) {
+ finish();
+ return new RwsState(c);
+ } else {
+ return new SearchWordState(this);
+ }
+ }
+ }
+
+
+ private class RwsState extends State {
+ public RwsState(char c) {
+ super(Token.RWS, c);
+ }
+ @Override
+ public State nextChar(char c) {
+ if (isWhitespace(c)) {
+ return allowed(c);
+ } else if (c == 'O' || c == 'o') {
+ return new OrState(c);
+ } else if (c == 'A' || c == 'a') {
+ return new AndState(c);
+ } else {
+ return new SearchExpressionState().init(c);
+ }
+ }
+ }
+
+ // TODO (mibo): add (new) parse exception
+ public List<SearchQueryToken> tokenize(String searchQuery) {
+ char[] chars = searchQuery.toCharArray();
+
+ State state = new SearchExpressionState();
+ List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
+ for (char aChar : chars) {
+ State next = state.next(aChar);
+ if (state.isFinished() && next != state) {
+ states.add(state);
+ }
+ state = next;
+ }
+
+ if(state.next(State.EOF).isFinished()) {
+ states.add(state);
+ } else {
+ throw new IllegalStateException("State: " + state + " not finished and list is: " + states.toString());
+ }
+
+ return states;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/SearchOptionImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/SearchOptionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/SearchOptionImpl.java
index ec42147..51323a8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/SearchOptionImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/SearchOptionImpl.java
@@ -24,13 +24,18 @@ import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
public class SearchOptionImpl extends SystemQueryOptionImpl implements SearchOption {
+ private SearchExpression searchExpression;
+
public SearchOptionImpl() {
setKind(SystemQueryOptionKind.SEARCH);
}
@Override
public SearchExpression getSearchExpression() {
- return null;
+ return searchExpression;
}
+ public void setSearchExpression(SearchExpression searchExpression) {
+ this.searchExpression = searchExpression;
+ }
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
new file mode 100644
index 0000000..81147ba
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -0,0 +1,30 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.junit.Test;
+
+public class SearchParserTest {
+
+ @Test
+ public void basicParsing() {
+ SearchParser parser = new SearchParser();
+ parser.parse("ESAllPrim", "abc");
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
new file mode 100644
index 0000000..15d35df
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -0,0 +1,388 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token.*;
+
+public class SearchTokenizerTest {
+
+ private boolean logEnabled = false;
+
+ @Test
+ public void testParse() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ //
+ result = tokenizer.tokenize("abc");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+
+ result = tokenizer.tokenize("NOT abc");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(NOT, result.get(0).getToken());
+ Assert.assertEquals(WORD, result.get(1).getToken());
+
+ result = tokenizer.tokenize("(abc)");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(OPEN, result.get(0).getToken());
+ Assert.assertEquals(WORD, result.get(1).getToken());
+ Assert.assertEquals(CLOSE, result.get(2).getToken());
+
+ result = tokenizer.tokenize("((abc))");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(OPEN, result.get(0).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+ Assert.assertEquals(CLOSE, result.get(4).getToken());
+ }
+
+ @Test
+ public void parseWords() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ //
+ result = tokenizer.tokenize("abc");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+
+ //
+ result = tokenizer.tokenize("9988abs");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ }
+
+ @Test
+ public void parsePhrase() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ //
+ result = tokenizer.tokenize("'abc'");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(PHRASE, result.get(0).getToken());
+
+ //
+ result = tokenizer.tokenize("'9988 abs'");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(PHRASE, result.get(0).getToken());
+ Assert.assertEquals("'9988 abs'", result.get(0).getLiteral());
+
+ //
+ result = tokenizer.tokenize("'99_88.'");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(PHRASE, result.get(0).getToken());
+ Assert.assertEquals("'99_88.'", result.get(0).getLiteral());
+ }
+
+ @Test
+ public void testParseNot() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ result = tokenizer.tokenize("NOT abc");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(NOT, result.get(0).getToken());
+ Assert.assertEquals(WORD, result.get(1).getToken());
+ }
+
+ @Test
+ public void testParseOr() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ result = tokenizer.tokenize("abc OR xyz");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(OR, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+
+ result = tokenizer.tokenize("abc OR xyz OR 123");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(OR, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+ Assert.assertEquals(OR, result.get(3).getToken());
+ Assert.assertEquals(WORD, result.get(4).getToken());
+ }
+
+ @Test
+ public void testParseAnd() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ result = tokenizer.tokenize("abc AND xyz");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+
+ result = tokenizer.tokenize("abc AND xyz AND 123");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+ Assert.assertEquals(AND, result.get(3).getToken());
+ Assert.assertEquals(WORD, result.get(4).getToken());
+
+ result = tokenizer.tokenize("abc AND 'x-y_z' AND 123");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(PHRASE, result.get(2).getToken());
+ Assert.assertEquals("'x-y_z'", result.get(2).getLiteral());
+ Assert.assertEquals(AND, result.get(3).getToken());
+ Assert.assertEquals(WORD, result.get(4).getToken());
+ }
+
+ @Test
+ public void testParseAndOr() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ result = tokenizer.tokenize("abc AND xyz OR 123");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+ Assert.assertEquals(OR, result.get(3).getToken());
+ Assert.assertEquals(WORD, result.get(4).getToken());
+
+ SearchValidator.init("abc AND ANDsomething")
+ .addExpected(WORD, AND, WORD).validate();
+ }
+
+
+ @Test
+ public void parseCombinations() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+
+ result = tokenizer.tokenize("abc AND NOT xyz OR 123");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Iterator<SearchQueryToken> it = result.iterator();
+ Assert.assertEquals(WORD, it.next().getToken());
+ Assert.assertEquals(AND, it.next().getToken());
+ Assert.assertEquals(NOT, it.next().getToken());
+ Assert.assertEquals(WORD, it.next().getToken());
+ Assert.assertEquals(OR, it.next().getToken());
+ Assert.assertEquals(WORD, it.next().getToken());
+
+ SearchValidator.init("foo AND bar OR foo AND baz OR that AND bar OR that AND baz")
+ .addExpected(WORD, "foo").addExpected(AND)
+ .addExpected(WORD, "bar").addExpected(OR)
+ .addExpected(WORD, "foo").addExpected(AND)
+ .addExpected(WORD, "baz").addExpected(OR)
+ .addExpected(WORD, "that").addExpected(AND)
+ .addExpected(WORD, "bar").addExpected(OR)
+ .addExpected(WORD, "that").addExpected(AND)
+ .addExpected(WORD, "baz")
+ .validate();
+
+
+ SearchValidator.init("(foo OR that) AND (bar OR baz)").enableLogging()
+ .addExpected(OPEN)
+ .addExpected(WORD, "foo").addExpected(OR).addExpected(WORD, "that")
+ .addExpected(CLOSE).addExpected(AND).addExpected(OPEN)
+ .addExpected(WORD, "bar").addExpected(OR).addExpected(WORD, "baz")
+ .addExpected(CLOSE)
+ .validate();
+ }
+
+
+ @Test
+ public void parseSpecial() throws Exception {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result;
+ Iterator<SearchQueryToken> it;
+
+ result = tokenizer.tokenize("NOT abc AND nothing");
+ log(result.toString());
+ it = result.iterator();
+ Assert.assertEquals(NOT, it.next().getToken());
+ Assert.assertEquals(WORD, it.next().getToken());
+ Assert.assertEquals(AND, it.next().getToken());
+ Assert.assertEquals(WORD, it.next().getToken());
+
+ result = tokenizer.tokenize("abc AND andsomething");
+ log(result.toString());
+ it = result.iterator();
+ Assert.assertEquals(WORD, it.next().getToken());
+ Assert.assertEquals(AND, it.next().getToken());
+ Assert.assertEquals(WORD, it.next().getToken());
+
+ result = tokenizer.tokenize("abc OR orsomething");
+ log(result.toString());
+ it = result.iterator();
+ Assert.assertEquals(WORD, it.next().getToken());
+ Assert.assertEquals(OR, it.next().getToken());
+ Assert.assertEquals(WORD, it.next().getToken());
+
+ SearchValidator.init("abc AND ANDsomething")
+ .addExpected(WORD, AND, WORD).validate();
+ }
+
+ @Test
+ public void moreMixedTests() {
+ validate("abc");
+ validate("NOT abc");
+
+ validate("abc AND def");
+ validate("abc OR def");
+ validate("abc def");
+
+ validate("abc AND def AND ghi", WORD, AND, WORD, AND, WORD);
+ validate("abc AND def OR ghi");
+ validate("abc AND def ghi");
+
+ validate("abc OR def AND ghi");
+ validate("abc OR def OR ghi");
+ validate("abc OR def ghi");
+
+ validate("abc def AND ghi");
+ validate("abc def OR ghi");
+ validate("abc def ghi");
+
+ // mixed not
+ validate(" abc def AND ghi");
+ validate("NOT abc NOT def OR NOT ghi");
+ validate(" abc def NOT ghi");
+
+ // parenthesis
+ validate("(abc)");
+ validate("(abc AND def)");
+ validate("(abc AND def) OR ghi ");
+ validate("(abc AND def) ghi ");
+ validate("abc AND (def OR ghi)");
+ validate("abc AND (def ghi)");
+ }
+
+ public boolean validate(String query) {
+ return new SearchValidator(query).validate();
+ }
+
+ public boolean validate(String query, SearchQueryToken.Token ... tokens) {
+ SearchValidator sv = new SearchValidator(query);
+ for (SearchQueryToken.Token token : tokens) {
+ sv.addExpected(token);
+ }
+ return sv.validate();
+ }
+
+ private static class SearchValidator {
+ private List<Tuple> validations = new ArrayList<Tuple>();
+ private boolean log;
+ private final String searchQuery;
+ private class Tuple {
+ final SearchQueryToken.Token token;
+ final String literal;
+ public Tuple(SearchQueryToken.Token token, String literal) {
+ this.token = token;
+ this.literal = literal;
+ }
+ public Tuple(SearchQueryToken.Token token) {
+ this(token, null);
+ }
+ }
+
+ private SearchValidator(String searchQuery) {
+ this.searchQuery = searchQuery;
+ }
+
+ private static SearchValidator init(String searchQuery) {
+ return new SearchValidator(searchQuery);
+ }
+ private SearchValidator enableLogging() {
+ log = true;
+ return this;
+ }
+ private SearchValidator addExpected(SearchQueryToken.Token token, String literal) {
+ validations.add(new Tuple(token, literal));
+ return this;
+ }
+ private SearchValidator addExpected(SearchQueryToken.Token ... token) {
+ for (SearchQueryToken.Token t : token) {
+ validations.add(new Tuple(t));
+ }
+ return this;
+ }
+ private boolean validate() {
+ SearchTokenizer tokenizer = new SearchTokenizer();
+ List<SearchQueryToken> result = tokenizer.tokenize(searchQuery);
+ Assert.assertNotNull(result);
+ if(log) {
+ System.out.println(result);
+ }
+ if(validations.size() != 0) {
+ Assert.assertEquals(validations.size(), result.size());
+
+ Iterator<Tuple> validationIt = validations.iterator();
+ for (SearchQueryToken iToken : result) {
+ Tuple validation = validationIt.next();
+ Assert.assertEquals(validation.token, iToken.getToken());
+ if(validation.literal != null) {
+ Assert.assertEquals(validation.literal, iToken.getLiteral());
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+
+
+
+ private void log(Object ... toString) {
+ if(logEnabled) {
+ System.out.println("------------");
+ if(toString == null || toString.length <= 1) {
+ System.out.println(toString == null? "NULL": (toString.length == 0? "EMPTY ARRAY": toString[0]));
+ } else {
+ int count = 1;
+ for (Object o : toString) {
+ System.out.println(count++ + ": " + o);
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/452ebcbd/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index 6f1c4ad..259b61f 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -1165,8 +1165,9 @@ public class TestFullResourcePath {
.isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
// $search is currently not implemented. Please change this exception if the implementation is done.
- testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
- .isExSemantic(MessageKeys.NOT_IMPLEMENTED);
+ // FIXME (151106:mibo): check after finish of OLINGO-568
+// testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
+// .isExSemantic(MessageKeys.NOT_IMPLEMENTED);
testUri.run("ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()")
.isKind(UriInfoKind.resource)
@@ -5363,12 +5364,12 @@ public class TestFullResourcePath {
testUri.run("ESTwoKeyNav", "$search= abc def NOT ghi");
// parenthesis
- testUri.run("ESTwoKeyNav", "$search= (abc)");
- testUri.run("ESTwoKeyNav", "$search= (abc AND def)");
- testUri.run("ESTwoKeyNav", "$search= (abc AND def) OR ghi ");
- testUri.run("ESTwoKeyNav", "$search= (abc AND def) ghi ");
- testUri.run("ESTwoKeyNav", "$search= abc AND (def OR ghi)");
- testUri.run("ESTwoKeyNav", "$search= abc AND (def ghi)");
+ testUri.run("ESTwoKeyNav", "$search=(abc)");
+ testUri.run("ESTwoKeyNav", "$search=(abc AND def)");
+ testUri.run("ESTwoKeyNav", "$search=(abc AND def) OR ghi ");
+ testUri.run("ESTwoKeyNav", "$search=(abc AND def) ghi ");
+ testUri.run("ESTwoKeyNav", "$search=abc AND (def OR ghi)");
+ testUri.run("ESTwoKeyNav", "$search=abc AND (def ghi)");
}
@Test
[22/23] olingo-odata4 git commit: [OLINGO-568] Merge branch
'OLINGO-568_SearchParser_Draft'
Posted by mi...@apache.org.
[OLINGO-568] Merge branch 'OLINGO-568_SearchParser_Draft'
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/1a59a580
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/1a59a580
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/1a59a580
Branch: refs/heads/master
Commit: 1a59a5804b16c714f5c9354ddd5b2c4a93987c1e
Parents: be3b10a 6235f3a
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Nov 17 15:31:44 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Nov 17 15:31:44 2015 +0100
----------------------------------------------------------------------
.../tecsvc/client/SystemQueryOptionITCase.java | 42 +-
.../queryoption/search/SearchExpression.java | 14 +-
.../api/uri/queryoption/search/SearchUnary.java | 5 +-
.../olingo/server/core/uri/parser/Parser.java | 15 +-
.../uri/parser/search/SearchBinaryImpl.java | 56 ++
.../uri/parser/search/SearchExpressionImpl.java | 58 ++
.../core/uri/parser/search/SearchParser.java | 196 +++++++
.../parser/search/SearchParserException.java | 54 ++
.../uri/parser/search/SearchQueryToken.java | 26 +
.../core/uri/parser/search/SearchTermImpl.java | 39 ++
.../core/uri/parser/search/SearchTokenizer.java | 571 +++++++++++++++++++
.../parser/search/SearchTokenizerException.java | 47 ++
.../core/uri/parser/search/SearchUnaryImpl.java | 46 ++
.../core/uri/queryoption/SearchOptionImpl.java | 7 +-
.../search/SearchParserAndTokenizerTest.java | 198 +++++++
.../uri/parser/search/SearchParserTest.java | 248 ++++++++
.../uri/parser/search/SearchTokenizerTest.java | 500 ++++++++++++++++
.../processor/TechnicalEntityProcessor.java | 2 +
.../tecsvc/processor/TechnicalProcessor.java | 3 +-
.../queryoptions/options/SearchHandler.java | 93 +++
.../core/uri/antlr/TestFullResourcePath.java | 19 +-
21 files changed, 2211 insertions(+), 28 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1a59a580/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------
diff --cc lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index c5857c7,d6cb557..d12b853
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@@ -58,7 -55,7 +58,8 @@@ import org.apache.olingo.server.core.ur
import org.apache.olingo.server.core.uri.antlr.UriParserParser.OrderByEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.PathSegmentEOFContext;
import org.apache.olingo.server.core.uri.antlr.UriParserParser.SelectEOFContext;
+ import org.apache.olingo.server.core.uri.parser.search.SearchParser;
+import org.apache.olingo.server.core.uri.queryoption.AliasQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CountOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.CustomQueryOptionImpl;
import org.apache.olingo.server.core.uri.queryoption.ExpandOptionImpl;
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1a59a580/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
[11/23] olingo-odata4 git commit: [OLINGO-568] Removed implicit and
and added unicode for words
Posted by mi...@apache.org.
[OLINGO-568] Removed implicit and and added unicode for words
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/ba5220ab
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/ba5220ab
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/ba5220ab
Branch: refs/heads/master
Commit: ba5220ab4a74d0c5aaff9fe1b72632e2a8bc8778
Parents: 37c5827
Author: mibo <mi...@apache.org>
Authored: Wed Nov 11 20:36:51 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Wed Nov 11 20:58:11 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchTokenizer.java | 169 +++++++++++++------
.../uri/parser/search/SearchTokenizerTest.java | 168 ++++++++++--------
2 files changed, 212 insertions(+), 125 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ba5220ab/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 1ec4df1..9288981 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -73,11 +73,6 @@ public class SearchTokenizer {
return this;
}
- public State finish(Token token) {
- this.token = token;
- return finish();
- }
-
public boolean isFinished() {
return finished;
}
@@ -90,23 +85,40 @@ public class SearchTokenizer {
return this;
}
- static boolean isAllowedChar(final char character) {
+ static boolean isAllowedWord(final char character) {
// TODO mibo: add missing allowed characters
- return CHAR_A <= character && character <= 'Z' // case A..Z
- || 'a' <= character && character <= 'z' // case a..z
- || '0' <= character && character <= '9'; // case 0..9
+ int type = Character.getType(character);
+ return (type == Character.LETTER_NUMBER
+ || type == Character.LOWERCASE_LETTER
+ || type == Character.MODIFIER_LETTER
+ || type == Character.OTHER_LETTER
+ || type == Character.TITLECASE_LETTER
+ || type == Character.UPPERCASE_LETTER);
}
/**
- * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
- * qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
+ * qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
+ * pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
+ * / "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
+ * / "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
+ *
+ * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
+ *
+ * escape = "\" / "%5C" ; reverse solidus U+005C
+ * quotation-mark = DQUOTE / "%22"
+ *
+ * ALPHA = %x41-5A / %x61-7A
+ * DIGIT = %x30-39
+ * DQUOTE = %x22
+ *
* @param character which is checked
* @return true if character is allowed for a phrase
*/
static boolean isAllowedPhrase(final char character) {
// FIXME mibo: check missing
- return isAllowedChar(character)
+ return isAlphaOrDigit(character)
|| character == '-'
|| character == '.'
|| character == '_'
@@ -119,6 +131,12 @@ public class SearchTokenizer {
|| character == '=';
}
+ private static boolean isAlphaOrDigit(char character) {
+ return 'A' <= character && character <= 'Z' // case A..Z
+ || 'a' <= character && character <= 'z' // case a..z
+ || '0' <= character && character <= '9'; // case 0..9
+ }
+
//BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
//RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
static boolean isWhitespace(final char character) {
@@ -173,15 +191,12 @@ public class SearchTokenizer {
public SearchExpressionState() {
super(null);
}
- public SearchExpressionState(String initLiteral) {
- super(null, initLiteral);
- }
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (c == CHAR_OPEN) {
return new OpenState();
} else if (isWhitespace(c)) {
- return new RwsImplicitAndOrState();
+ return new RwsState();
} else if(c == CHAR_CLOSE) {
return new CloseState();
} else {
@@ -205,7 +220,7 @@ public class SearchTokenizer {
return new NotState(c);
} else if (c == QUOTATION_MARK) {
return new SearchPhraseState(c);
- } else if (isAllowedChar(c)) {
+ } else if (isAllowedWord(c)) {
return new SearchWordState(c);
}
return forbidden(c);
@@ -219,21 +234,30 @@ public class SearchTokenizer {
private class SearchWordState extends LiteralState {
public SearchWordState(char c) throws SearchTokenizerException {
super(Token.WORD, c);
+ if(!isAllowedWord(c)) {
+ forbidden(c);
+ }
}
- public SearchWordState(State toConsume) {
+ public SearchWordState(State toConsume) throws SearchTokenizerException {
super(Token.WORD, toConsume.getLiteral());
+ char[] chars = literal.toString().toCharArray();
+ for (char aChar : chars) {
+ if(!isAllowedWord(aChar)) {
+ forbidden(aChar);
+ }
+ }
}
@Override
public State nextChar(char c) throws SearchTokenizerException {
- if (isAllowedChar(c)) {
+ if (isAllowedWord(c)) {
return allowed(c);
} else if (c == CHAR_CLOSE) {
finish();
return new CloseState();
} else if (isWhitespace(c)) {
finish();
- return new RwsImplicitAndOrState();
+ return new RwsState();
}
return forbidden(c);
}
@@ -304,13 +328,52 @@ public class SearchTokenizer {
}
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
if (literal.length() == 1 && c == CHAR_O) {
return allowed(c);
} else if (literal.length() == 2 && c == CHAR_T) {
return allowed(c);
} else if(literal.length() == 3 && isWhitespace(c)) {
finish();
+ return new BeforePhraseOrWordRwsState();
+ }
+ return forbidden(c);
+ }
+ }
+ private class AndState extends LiteralState {
+ public AndState(char c) throws SearchTokenizerException {
+ super(Token.AND, c);
+ if(c != CHAR_A) {
+ forbidden(c);
+ }
+ }
+ @Override
+ public State nextChar(char c) throws SearchTokenizerException {
+ if (literal.length() == 1 && c == CHAR_N) {
+ return allowed(c);
+ } else if (literal.length() == 2 && c == CHAR_D) {
+ return allowed(c);
+ } else if(literal.length() == 3 && isWhitespace(c)) {
+ finish();
+ return new BeforeSearchExpressionRwsState();
+ } else {
+ return new SearchWordState(this);
+ }
+ }
+ }
+ private class OrState extends LiteralState {
+ public OrState(char c) throws SearchTokenizerException {
+ super(Token.OR, c);
+ if(c != CHAR_O) {
+ forbidden(c);
+ }
+ }
+ @Override
+ public State nextChar(char c) throws SearchTokenizerException {
+ if (literal.length() == 1 && (c == CHAR_R)) {
+ return allowed(c);
+ } else if(literal.length() == 2 && isWhitespace(c)) {
+ finish();
return new BeforeSearchExpressionRwsState();
} else {
return new SearchWordState(this);
@@ -334,47 +397,53 @@ public class SearchTokenizer {
}
}
- // implicit and
- private class RwsImplicitAndOrState extends LiteralState {
- private boolean noneRws = false;
- public RwsImplicitAndOrState() {
+ private class BeforePhraseOrWordRwsState extends State {
+ public BeforePhraseOrWordRwsState() {
super(null);
}
@Override
public State nextChar(char c) throws SearchTokenizerException {
- if (!noneRws && isWhitespace(c)) {
- return allowed(c);
- } else if (c == CHAR_O) {
- noneRws = true;
+ if (isWhitespace(c)) {
return allowed(c);
- } else if (literal.length() == 1 && c == CHAR_R) {
+ } else if(c == '"') {
+ return new SearchPhraseState(c);
+ } else {
+ return new SearchWordState(c);
+ }
+ }
+ }
+
+ private class RwsState extends State {
+ public RwsState() {
+ super(null);
+ }
+ @Override
+ public State nextChar(char c) throws SearchTokenizerException {
+ if (isWhitespace(c)) {
return allowed(c);
- } else if (literal.length() == 2 && isWhitespace(c)) {
- finish(Token.OR);
- return new BeforeSearchExpressionRwsState();
+ } else if (c == CHAR_O) {
+ return new OrState(c);
} else if (c == CHAR_A) {
- noneRws = true;
- return allowed(c);
- } else if (literal.length() == 1 && c == CHAR_N) {
- return allowed(c);
- } else if (literal.length() == 2 && c == CHAR_D) {
- return allowed(c);
- } else if(literal.length() == 3 && isWhitespace(c)) {
- finish(Token.AND);
- return new BeforeSearchExpressionRwsState();
- } else if(noneRws) {
- finish(Token.AND);
- return new SearchWordState(this);
+ return new AndState(c);
} else {
- finish(Token.AND);
- return new SearchExpressionState(literal.toString()).init(c);
+ return new SearchExpressionState().init(c);
}
}
}
- // TODO (mibo): add (new) parse exception
- public List<SearchQueryToken> tokenize(String searchQuery) throws SearchTokenizerException {
- char[] chars = searchQuery.toCharArray();
+ /**
+ * Take the search query and split into according SearchQueryToken.
+ * Before split into tokens the given search query is 'trimmed'.
+ *
+ * @param searchQuery search query to be tokenized
+ * @return list of tokens
+ * @throws SearchTokenizerException if something in query is not valid
+ * (based on OData search query ABNF)
+ */
+ public List<SearchQueryToken> tokenize(final String searchQuery)
+ throws SearchTokenizerException {
+
+ char[] chars = searchQuery.trim().toCharArray();
State state = new SearchExpressionState();
List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ba5220ab/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index ea3cab9..828b4c4 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -29,8 +29,6 @@ import static org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.T
public class SearchTokenizerTest {
- private boolean logEnabled = false;
-
@Test
public void parseBasics() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
@@ -39,25 +37,25 @@ public class SearchTokenizerTest {
//
result = tokenizer.tokenize("abc");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
result = tokenizer.tokenize("NOT abc");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(NOT, result.get(0).getToken());
Assert.assertEquals(WORD, result.get(1).getToken());
result = tokenizer.tokenize("(abc)");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(OPEN, result.get(0).getToken());
Assert.assertEquals(WORD, result.get(1).getToken());
Assert.assertEquals(CLOSE, result.get(2).getToken());
result = tokenizer.tokenize("((abc))");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(OPEN, result.get(0).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
Assert.assertEquals(CLOSE, result.get(4).getToken());
@@ -71,13 +69,13 @@ public class SearchTokenizerTest {
//
result = tokenizer.tokenize("abc");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
//
- result = tokenizer.tokenize("9988abs");
+ result = tokenizer.tokenize("anotherWord\u1234");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
}
@@ -86,29 +84,29 @@ public class SearchTokenizerTest {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
- SearchValidator.init("abc AND \"x-y_z\" AND 123").validate();
+ SearchValidator.init("abc AND \"x-y_z\" AND olingo").validate();
//
result = tokenizer.tokenize("\"abc\"");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(PHRASE, result.get(0).getToken());
//
result = tokenizer.tokenize("\"9988 abs\"");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(PHRASE, result.get(0).getToken());
Assert.assertEquals("\"9988 abs\"", result.get(0).getLiteral());
//
result = tokenizer.tokenize("\"99_88.\"");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(PHRASE, result.get(0).getToken());
Assert.assertEquals("\"99_88.\"", result.get(0).getLiteral());
- SearchValidator.init("abc or \"xyz\"").addExpected(WORD, AND, WORD, AND, PHRASE).validate();
+ SearchValidator.init("abc or \"xyz\"").addExpected(WORD, WORD, PHRASE).validate();
}
@Test
@@ -118,11 +116,14 @@ public class SearchTokenizerTest {
result = tokenizer.tokenize("NOT abc");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(NOT, result.get(0).getToken());
Assert.assertEquals(WORD, result.get(1).getToken());
- SearchValidator.init("not abc").addExpected(WORD, AND, WORD).validate();
+ SearchValidator.init("not abc").addExpected(WORD, WORD).validate();
+ SearchValidator.init("NOT abc").addExpected(NOT, WORD).validate();
+ SearchValidator.init("NOT \"abc\"").addExpected(NOT, PHRASE).validate();
+ SearchValidator.init("NOT (sdf)").validate(SearchTokenizerException.class);
}
@Test
@@ -132,30 +133,30 @@ public class SearchTokenizerTest {
result = tokenizer.tokenize("abc OR xyz");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(OR, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
- result = tokenizer.tokenize("abc OR xyz OR 123");
+ result = tokenizer.tokenize("abc OR xyz OR olingo");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(OR, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
Assert.assertEquals(OR, result.get(3).getToken());
Assert.assertEquals(WORD, result.get(4).getToken());
- SearchValidator.init("abc or xyz").addExpected(WORD, AND, WORD, AND, WORD).validate();
+ SearchValidator.init("abc or xyz").addExpected(WORD, WORD, WORD).validate();
}
@Test
public void parseImplicitAnd() throws SearchTokenizerException {
- SearchValidator.init("a b").addExpected(WORD, AND, WORD).validate();
- SearchValidator.init("a b OR c").addExpected(WORD, AND, WORD, OR, WORD).validate();
- SearchValidator.init("a bc OR c").addExpected(WORD, AND, WORD, OR, WORD).validate();
- SearchValidator.init("a bc c").addExpected(WORD, AND, WORD, AND, WORD).validate();
- SearchValidator.init("(a OR x) bc c").addExpected(OPEN, WORD, OR, WORD, CLOSE, AND, WORD, AND, WORD).validate();
+ SearchValidator.init("a b").addExpected(WORD, WORD).validate();
+ SearchValidator.init("a b OR c").addExpected(WORD, WORD, OR, WORD).validate();
+ SearchValidator.init("a bc OR c").addExpected(WORD, WORD, OR, WORD).validate();
+ SearchValidator.init("a bc c").addExpected(WORD, WORD, WORD).validate();
+ SearchValidator.init("(a OR x) bc c").addExpected(OPEN, WORD, OR, WORD, CLOSE, WORD, WORD).validate();
}
@Test
@@ -165,7 +166,7 @@ public class SearchTokenizerTest {
result = tokenizer.tokenize("abc AND xyz");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
@@ -173,34 +174,31 @@ public class SearchTokenizerTest {
// no lower case allowed for AND
result = tokenizer.tokenize("abc and xyz");
Assert.assertNotNull(result);
- Assert.assertEquals(5, result.size());
- log(result.toString());
+ Assert.assertEquals(3, result.size());
+
Assert.assertEquals(WORD, result.get(0).getToken());
- Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
- Assert.assertEquals(AND, result.get(3).getToken());
- Assert.assertEquals(WORD, result.get(4).getToken());
// implicit AND
result = tokenizer.tokenize("abc xyz");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
- Assert.assertEquals(AND, result.get(1).getToken());
- Assert.assertEquals(WORD, result.get(2).getToken());
+ Assert.assertEquals(WORD, result.get(1).getToken());
- result = tokenizer.tokenize("abc AND xyz AND 123");
+ result = tokenizer.tokenize("abc AND xyz AND olingo");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
Assert.assertEquals(AND, result.get(3).getToken());
Assert.assertEquals(WORD, result.get(4).getToken());
- result = tokenizer.tokenize("abc AND \"x-y_z\" AND 123");
+ result = tokenizer.tokenize("abc AND \"x-y_z\" AND olingo");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(PHRASE, result.get(2).getToken());
@@ -214,9 +212,9 @@ public class SearchTokenizerTest {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
- result = tokenizer.tokenize("abc AND xyz OR 123");
+ result = tokenizer.tokenize("abc AND xyz OR olingo");
Assert.assertNotNull(result);
- log(result.toString());
+
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
@@ -233,9 +231,9 @@ public class SearchTokenizerTest {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
- result = tokenizer.tokenize("abc AND NOT xyz OR 123");
+ result = tokenizer.tokenize("abc AND NOT xyz OR olingo");
Assert.assertNotNull(result);
- log(result.toString());
+
Iterator<SearchQueryToken> it = result.iterator();
Assert.assertEquals(WORD, it.next().getToken());
Assert.assertEquals(AND, it.next().getToken());
@@ -273,7 +271,7 @@ public class SearchTokenizerTest {
Iterator<SearchQueryToken> it;
result = tokenizer.tokenize("NOT abc AND nothing");
- log(result.toString());
+
it = result.iterator();
Assert.assertEquals(NOT, it.next().getToken());
Assert.assertEquals(WORD, it.next().getToken());
@@ -281,7 +279,7 @@ public class SearchTokenizerTest {
Assert.assertEquals(WORD, it.next().getToken());
result = tokenizer.tokenize("abc AND andsomething");
- log(result.toString());
+
it = result.iterator();
Assert.assertEquals(WORD, it.next().getToken());
Assert.assertEquals(AND, it.next().getToken());
@@ -291,17 +289,47 @@ public class SearchTokenizerTest {
.addExpected(WORD, AND, WORD).validate();
SearchValidator.init("abc ANDsomething")
- .addExpected(WORD, AND, WORD).validate();
+ .addExpected(WORD, WORD).validate();
SearchValidator.init("abc ORsomething")
- .addExpected(WORD, AND, WORD).validate();
+ .addExpected(WORD, WORD).validate();
SearchValidator.init("abc OR orsomething")
.addExpected(WORD, OR, WORD).validate();
SearchValidator.init("abc OR ORsomething")
.addExpected(WORD, OR, WORD).validate();
+ }
+
+ @Test
+ public void unicodeInWords() throws Exception {
+ // Ll, Lm, Lo, Lt, Lu, Nl
+ SearchValidator.init("abc OR Ll\u01E3Lm\u02B5Lo\u1BE4Lt\u01F2Lu\u03D3Nl\u216F")
+ .addExpected(WORD, OR, WORD).validate();
+ }
+ /**
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
+ * qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
+ * pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
+ * / "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
+ * / "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
+ *
+ * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
+ *
+ * escape = "\" / "%5C" ; reverse solidus U+005C
+ * quotation-mark = DQUOTE / "%22"
+ * ALPHA = %x41-5A / %x61-7A
+ * DIGIT = %x30-39
+ * DQUOTE = %x22
+ *
+ * @throws Exception
+ */
+ @Test
+ public void characterInPhrase() throws Exception {
+ SearchValidator.init("\"123\" OR \"ALPHA-._~\"")
+ .addExpected(PHRASE, OR, PHRASE).validate();
}
@Test
@@ -311,32 +339,32 @@ public class SearchTokenizerTest {
validate("abc AND def");
validate("abc OR def");
- validate("abc def");
+ validate("abc def", WORD, WORD);
validate("abc AND def AND ghi", WORD, AND, WORD, AND, WORD);
validate("abc AND def OR ghi");
validate("abc AND def ghi");
- validate("abc OR def AND ghi");
- validate("abc OR def OR ghi");
- validate("abc OR def ghi");
+ validate("abc OR def AND ghi", WORD, OR, WORD, AND, WORD);
+ validate("abc OR def OR ghi", WORD, OR, WORD, OR, WORD);
+ validate("abc OR def ghi", WORD, OR, WORD, WORD);
validate("abc def AND ghi");
validate("abc def OR ghi");
validate("abc def ghi");
// mixed not
- validate(" abc def AND ghi");
- validate("NOT abc NOT def OR NOT ghi");
- validate(" abc def NOT ghi");
+ SearchValidator.init(" abc def AND ghi").validate(WORD, WORD, AND, WORD);
+ validate("NOT abc NOT def OR NOT ghi", NOT, WORD, NOT, WORD, OR, NOT, WORD);
+ validate(" abc def NOT ghi", WORD, WORD, NOT, WORD);
// parenthesis
- validate("(abc)");
- validate("(abc AND def)");
- validate("(abc AND def) OR ghi");
- validate("(abc AND def) ghi");
- validate("abc AND (def OR ghi)");
- validate("abc AND (def ghi)");
+ validate("(abc)", OPEN, WORD, CLOSE);
+ validate("(abc AND def)", OPEN, WORD, AND, WORD, CLOSE);
+ validate("(abc AND def) OR ghi", OPEN, WORD, AND, WORD, CLOSE, OR, WORD);
+ validate("(abc AND def) ghi", OPEN, WORD, AND, WORD, CLOSE, WORD);
+ validate("abc AND (def OR ghi)", WORD, AND, OPEN, WORD, OR, WORD, CLOSE);
+ validate("abc AND (def ghi)", WORD, AND, OPEN, WORD, WORD, CLOSE);
}
@Test
@@ -363,6 +391,12 @@ public class SearchTokenizerTest {
private List<Tuple> validations = new ArrayList<Tuple>();
private boolean log;
private final String searchQuery;
+
+ public void validate(SearchQueryToken.Token... tokens) throws SearchTokenizerException {
+ addExpected(tokens);
+ validate();
+ }
+
private class Tuple {
final SearchQueryToken.Token token;
final String literal;
@@ -427,20 +461,4 @@ public class SearchTokenizerTest {
}
}
}
-
-
-
- private void log(Object ... toString) {
- if(logEnabled) {
- System.out.println("------------");
- if(toString == null || toString.length <= 1) {
- System.out.println(toString == null? "NULL": (toString.length == 0? "EMPTY ARRAY": toString[0]));
- } else {
- int count = 1;
- for (Object o : toString) {
- System.out.println(count++ + ": " + o);
- }
- }
- }
- }
}
\ No newline at end of file
[08/23] olingo-odata4 git commit: [OLINGO-568] Fixed issue with
implicit and
Posted by mi...@apache.org.
[OLINGO-568] Fixed issue with implicit and
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/f64abe13
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/f64abe13
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/f64abe13
Branch: refs/heads/master
Commit: f64abe136b0d8b6b8ec195319f2a5e3db98c27d5
Parents: 96483ae
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Nov 10 06:25:54 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Nov 10 06:25:54 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchTokenizer.java | 94 ++++++++------------
.../uri/parser/search/SearchTokenizerTest.java | 9 +-
2 files changed, 40 insertions(+), 63 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f64abe13/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 12af609..f393d22 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -73,6 +73,11 @@ public class SearchTokenizer {
return this;
}
+ public State finish(Token token) {
+ this.token = token;
+ return finish();
+ }
+
public boolean isFinished() {
return finished;
}
@@ -167,12 +172,15 @@ public class SearchTokenizer {
public SearchExpressionState() {
super(null);
}
+ public SearchExpressionState(String initLiteral) {
+ super(null, initLiteral);
+ }
@Override
public State nextChar(char c) {
if (c == CHAR_OPEN) {
return new OpenState();
} else if (isWhitespace(c)) {
- return new RwsImplicitAndState();
+ return new RwsImplicitAndOrState();
} else if(c == CHAR_CLOSE) {
return new CloseState();
} else {
@@ -224,7 +232,7 @@ public class SearchTokenizer {
return new CloseState();
} else if (isWhitespace(c)) {
finish();
- return new RwsImplicitAndState();
+ return new RwsImplicitAndOrState();
}
return forbidden(c);
}
@@ -254,14 +262,8 @@ public class SearchTokenizer {
allowed(c);
return new SearchExpressionState();
} else if (isWhitespace(c)) {
- if(isFinished()) {
- return new RwsImplicitAndState();
- }
return allowed(c);
} else if (c == CHAR_CLOSE) {
- if(isFinished()) {
- return new CloseState();
- }
return allowed(c);
}
return forbidden(c);
@@ -317,48 +319,6 @@ public class SearchTokenizer {
}
}
- private class AndState extends LiteralState {
- public AndState(char c) {
- super(Token.AND, c);
- if(c != CHAR_A) {
- forbidden(c);
- }
- }
- @Override
- public State nextChar(char c) {
- if (literal.length() == 1 && c == CHAR_N) {
- return allowed(c);
- } else if (literal.length() == 2 && c == CHAR_D) {
- return allowed(c);
- } else if(literal.length() == 3 && isWhitespace(c)) {
- finish();
- return new BeforeSearchExpressionRwsState();
- } else {
- return new SearchWordState(this);
- }
- }
- }
-
- private class OrState extends LiteralState {
- public OrState(char c) {
- super(Token.OR, c);
- if(c != CHAR_O) {
- forbidden(c);
- }
- }
- @Override
- public State nextChar(char c) {
- if (literal.length() == 1 && (c == CHAR_R)) {
- return allowed(c);
- } else if(literal.length() == 2 && isWhitespace(c)) {
- finish();
- return new BeforeSearchExpressionRwsState();
- } else {
- return new SearchWordState(this);
- }
- }
- }
-
// RWS 'OR' RWS searchExpr
// RWS [ 'AND' RWS ] searchExpr
private class BeforeSearchExpressionRwsState extends State {
@@ -376,21 +336,39 @@ public class SearchTokenizer {
}
// implicit and
- private class RwsImplicitAndState extends State {
- public RwsImplicitAndState() {
- super(Token.AND);
+ private class RwsImplicitAndOrState extends LiteralState {
+ private boolean noneRws = false;
+ public RwsImplicitAndOrState() {
+ super(null);
}
@Override
public State nextChar(char c) {
- if (isWhitespace(c)) {
+ if (!noneRws && isWhitespace(c)) {
return allowed(c);
} else if (c == CHAR_O) {
- return new OrState(c);
+ noneRws = true;
+ return allowed(c);
+ } else if (literal.length() == 1 && c == CHAR_R) {
+ return allowed(c);
+ } else if (literal.length() == 2 && isWhitespace(c)) {
+ finish(Token.OR);
+ return new BeforeSearchExpressionRwsState();
} else if (c == CHAR_A) {
- return new AndState(c);
+ noneRws = true;
+ return allowed(c);
+ } else if (literal.length() == 1 && c == CHAR_N) {
+ return allowed(c);
+ } else if (literal.length() == 2 && c == CHAR_D) {
+ return allowed(c);
+ } else if(literal.length() == 3 && isWhitespace(c)) {
+ finish(Token.AND);
+ return new BeforeSearchExpressionRwsState();
+ } else if(noneRws) {
+ finish(Token.AND);
+ return new SearchWordState(this);
} else {
- finish();
- return new SearchExpressionState().init(c);
+ finish(Token.AND);
+ return new SearchExpressionState(literal.toString()).init(c);
}
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/f64abe13/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 29287cd..548d3fd 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -290,12 +290,11 @@ public class SearchTokenizerTest {
SearchValidator.init("abc AND ANDsomething")
.addExpected(WORD, AND, WORD).validate();
- // FIXME (mibo): issue with implicit and
-// SearchValidator.init("abc ANDsomething").enableLogging()
-// .addExpected(WORD, AND, WORD).validate();
+ SearchValidator.init("abc ANDsomething")
+ .addExpected(WORD, AND, WORD).validate();
-// SearchValidator.init("abc ORsomething")
-// .addExpected(WORD, AND, WORD).validate();
+ SearchValidator.init("abc ORsomething")
+ .addExpected(WORD, AND, WORD).validate();
SearchValidator.init("abc OR orsomething")
.addExpected(WORD, OR, WORD).validate();
[15/23] olingo-odata4 git commit: [OLINGO-568] Added missing
SearchParser parse paths
Posted by mi...@apache.org.
[OLINGO-568] Added missing SearchParser parse paths
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/cef72e45
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/cef72e45
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/cef72e45
Branch: refs/heads/master
Commit: cef72e45ab0509310ed46c26d0c3df4a30885d5f
Parents: 40962a9
Author: mibo <mi...@apache.org>
Authored: Fri Nov 13 08:16:15 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Fri Nov 13 08:16:15 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchParser.java | 99 +++++++++++++-------
.../search/SearchParserAndTokenizerTest.java | 19 +++-
.../uri/parser/search/SearchParserTest.java | 9 +-
3 files changed, 85 insertions(+), 42 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cef72e45/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index 25c52f2..d5109a5 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -29,20 +29,20 @@ import java.util.List;
public class SearchParser {
private Iterator<SearchQueryToken> tokens;
- private SearchExpression root;
private SearchQueryToken token;
public SearchOption parse(String path, String value) {
SearchTokenizer tokenizer = new SearchTokenizer();
+ SearchExpression searchExpression;
try {
tokens = tokenizer.tokenize(value).iterator();
nextToken();
- root = processSearchExpression(null);
+ searchExpression = processSearchExpression(null);
} catch (SearchTokenizerException e) {
return null;
}
final SearchOptionImpl searchOption = new SearchOptionImpl();
- searchOption.setSearchExpression(root);
+ searchOption.setSearchExpression(searchExpression);
return searchOption;
}
@@ -57,26 +57,47 @@ public class SearchParser {
return left;
}
- if(token.getToken() == SearchQueryToken.Token.OPEN) {
+ SearchExpression expression = left;
+ if(isToken(SearchQueryToken.Token.OPEN)) {
processOpen();
- throw illegalState();
- } else if(token.getToken() == SearchQueryToken.Token.CLOSE) {
- processClose();
- throw illegalState();
- } else if(token.getToken() == SearchQueryToken.Token.NOT) {
- processNot();
- } else if(token.getToken() == SearchQueryToken.Token.PHRASE ||
- token.getToken() == SearchQueryToken.Token.WORD) {
- return processSearchExpression(processTerm());
- } else if(token.getToken() == SearchQueryToken.Token.AND) {
- SearchExpression se = processAnd(left);
- return processSearchExpression(se);
- } else if(token.getToken() == SearchQueryToken.Token.OR) {
- return processOr(left);
- } else {
+ expression = processSearchExpression(left);
+ validateToken(SearchQueryToken.Token.CLOSE);
+ processClose();
+ } else if(isTerm()) {
+ expression = processTerm();
+ }
+
+ if(isToken(SearchQueryToken.Token.AND) || isTerm()) {
+ expression = processAnd(expression);
+ } else if(isToken(SearchQueryToken.Token.OR)) {
+ expression = processOr(expression);
+ } else if(isEof()) {
+ return expression;
+ }
+ return expression;
+ }
+
+ private boolean isTerm() {
+ return isToken(SearchQueryToken.Token.NOT)
+ || isToken(SearchQueryToken.Token.PHRASE)
+ || isToken(SearchQueryToken.Token.WORD);
+ }
+
+ private boolean isEof() {
+ return token == null;
+ }
+
+ private boolean isToken(SearchQueryToken.Token toCheckToken) {
+ if(token == null) {
+ return false;
+ }
+ return token.getToken() == toCheckToken;
+ }
+
+ private void validateToken(SearchQueryToken.Token toValidateToken) {
+ if(!isToken(toValidateToken)) {
throw illegalState();
}
- throw illegalState();
}
private void processClose() {
@@ -88,13 +109,24 @@ public class SearchParser {
}
private SearchExpression processAnd(SearchExpression left) {
- nextToken();
- SearchExpression se = processTerm();
- return new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, se);
+ if(isToken(SearchQueryToken.Token.AND)) {
+ nextToken();
+ }
+ SearchExpression se = left;
+ if(isTerm()) {
+ se = processTerm();
+ se = new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, se);
+ return processSearchExpression(se);
+ } else {
+ se = processSearchExpression(se);
+ return new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, se);
+ }
}
public SearchExpression processOr(SearchExpression left) {
- nextToken();
+ if(isToken(SearchQueryToken.Token.OR)) {
+ nextToken();
+ }
SearchExpression se = processSearchExpression(left);
return new SearchBinaryImpl(left, SearchBinaryOperatorKind.OR, se);
}
@@ -103,8 +135,13 @@ public class SearchParser {
return new RuntimeException();
}
- private void processNot() {
+ private SearchExpression processNot() {
nextToken();
+ SearchExpression searchExpression = processTerm();
+ if(searchExpression.isSearchTerm()) {
+ return new SearchUnaryImpl(searchExpression.asSearchTerm());
+ }
+ throw illegalState();
}
private void nextToken() {
@@ -113,20 +150,18 @@ public class SearchParser {
} else {
token = null;
}
-// return null;
}
private SearchExpression processTerm() {
- if(token.getToken() == SearchQueryToken.Token.NOT) {
- return new SearchUnaryImpl(processPhrase());
+ if(isToken(SearchQueryToken.Token.NOT)) {
+ return processNot();
}
- if(token.getToken() == SearchQueryToken.Token.PHRASE) {
+ if(isToken(SearchQueryToken.Token.PHRASE)) {
return processPhrase();
- }
- if(token.getToken() == SearchQueryToken.Token.WORD) {
+ } else if(isToken(SearchQueryToken.Token.WORD)) {
return processWord();
}
- return null;
+ throw illegalState();
}
private SearchTermImpl processWord() {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cef72e45/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index 3ecd517..271b617 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -34,9 +34,6 @@ public class SearchParserAndTokenizerTest {
@Test
public void basicParsing() throws SearchTokenizerException {
-// SearchExpressionValidator.init("a AND b OR c").enableLogging()
-// .validate(with("a"));
-
SearchExpressionValidator.init("a")
.validate(with("a"));
SearchExpressionValidator.init("a AND b")
@@ -57,6 +54,22 @@ public class SearchParserAndTokenizerTest {
.validate("{'a' OR {'b' AND 'c'}}");
}
+ @Test
+ public void notParsing() throws Exception {
+ SearchExpressionValidator.init("NOT a AND b OR c")
+ .validate("{{{NOT 'a'} AND 'b'} OR 'c'}");
+ SearchExpressionValidator.init("a OR b AND NOT c")
+ .validate("{'a' OR {'b' AND {NOT 'c'}}}");
+ }
+
+ @Test
+ public void parenthesesParsing() throws Exception {
+ SearchExpressionValidator.init("a AND (b OR c)")
+ .validate("{'a' AND {'b' OR 'c'}}");
+ SearchExpressionValidator.init("(a OR b) AND NOT c")
+ .validate("{{'a' OR 'b'} AND {NOT 'c'}}");
+ }
+
@Ignore
@Test
public void sebuilder() {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cef72e45/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index ce37f3d..89b59b4 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -83,7 +83,6 @@ public class SearchParserTest extends SearchParser {
assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
- @Ignore
@Test
public void simpleImplicitAnd() {
SearchExpression se = run(Token.WORD, Token.WORD);
@@ -101,7 +100,6 @@ public class SearchParserTest extends SearchParser {
assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
- @Ignore
@Test
public void simpleBrackets() {
SearchExpression se = run(Token.OPEN, Token.WORD, Token.CLOSE);
@@ -115,7 +113,6 @@ public class SearchParserTest extends SearchParser {
assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
}
- @Ignore
@Test
public void simpleNot() {
SearchExpression se = run(Token.NOT, Token.WORD);
@@ -123,13 +120,12 @@ public class SearchParserTest extends SearchParser {
assertTrue(se.isSearchUnary());
assertEquals("word1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
- se = run(Token.NOT, Token.WORD);
- assertEquals("'phrase1'", se.toString());
+ se = run(Token.NOT, Token.PHRASE);
+ assertEquals("{NOT 'phrase1'}", se.toString());
assertTrue(se.isSearchUnary());
assertEquals("phrase1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
}
- @Ignore
@Test
public void precedenceLast() {
//word1 AND (word2 AND word3)
@@ -137,7 +133,6 @@ public class SearchParserTest extends SearchParser {
assertEquals("{'word1' AND {'word2' AND 'word3'}}", se.toString());
}
- @Ignore
@Test
public void precedenceFirst() {
//(word1 AND word2) AND word3
[12/23] olingo-odata4 git commit: [OLINGO-568] search parser tests
refactoring
Posted by mi...@apache.org.
[OLINGO-568] search parser tests refactoring
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/22d152fc
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/22d152fc
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/22d152fc
Branch: refs/heads/master
Commit: 22d152fc4c1681f91b2b4e545c005873e655290c
Parents: ba5220a
Author: Christian Amend <ch...@sap.com>
Authored: Thu Nov 12 13:58:11 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Nov 12 13:58:38 2015 +0100
----------------------------------------------------------------------
.../queryoption/search/SearchExpression.java | 14 +-
.../uri/parser/search/SearchBinaryImpl.java | 2 +-
.../uri/parser/search/SearchExpressionImpl.java | 58 +++++
.../core/uri/parser/search/SearchParser.java | 10 +-
.../core/uri/parser/search/SearchTermImpl.java | 4 +-
.../core/uri/parser/search/SearchUnaryImpl.java | 2 +-
.../search/SearchParserAndTokenizerTest.java | 171 ++++++++++++
.../uri/parser/search/SearchParserTest.java | 260 ++++++++++---------
.../uri/parser/search/SearchTokenizerTest.java | 2 +-
9 files changed, 387 insertions(+), 136 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchExpression.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchExpression.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchExpression.java
index ed66f5f..983919c 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchExpression.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchExpression.java
@@ -19,5 +19,17 @@
package org.apache.olingo.server.api.uri.queryoption.search;
public interface SearchExpression {
- //No additional methods needed for now.
+
+ boolean isSearchTerm();
+
+ SearchTerm asSearchTerm();
+
+ boolean isSearchBinary();
+
+ SearchBinary asSearchBinary();
+
+ boolean isSearchUnary();
+
+ SearchUnary asSearchUnary();
+
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
index 37b03c0..418d9e7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
@@ -22,7 +22,7 @@ import org.apache.olingo.server.api.uri.queryoption.search.SearchBinary;
import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
-public class SearchBinaryImpl implements SearchBinary {
+public class SearchBinaryImpl extends SearchExpressionImpl implements SearchBinary {
private final SearchBinaryOperatorKind operator;
private final SearchExpression left;
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchExpressionImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchExpressionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchExpressionImpl.java
new file mode 100644
index 0000000..ee5a197
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchExpressionImpl.java
@@ -0,0 +1,58 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinary;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
+
+public abstract class SearchExpressionImpl implements SearchExpression {
+
+ @Override
+ public boolean isSearchTerm() {
+ return this instanceof SearchTerm;
+ }
+
+ @Override
+ public SearchTerm asSearchTerm() {
+ return isSearchTerm() ? (SearchTerm) this : null;
+ }
+
+ @Override
+ public boolean isSearchBinary() {
+ return this instanceof SearchBinary;
+ }
+
+ @Override
+ public SearchBinary asSearchBinary() {
+ return isSearchBinary() ? (SearchBinary) this : null;
+ }
+
+ @Override
+ public boolean isSearchUnary() {
+ return this instanceof SearchUnary;
+ }
+
+ @Override
+ public SearchUnary asSearchUnary() {
+ return isSearchUnary() ? (SearchUnary) this : null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index 60fcd4b..5e26c35 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -28,8 +28,8 @@ import java.util.Iterator;
public class SearchParser {
- private Iterator<SearchQueryToken> tokens;
- private SearchExpression root;
+ protected Iterator<SearchQueryToken> tokens;
+ protected SearchExpression root;
// private SearchQueryToken currentToken;
public SearchOption parse(String path, String value) {
@@ -37,7 +37,7 @@ public class SearchParser {
try {
tokens = tokenizer.tokenize(value).iterator();
// currentToken = tokens.next();
- root = processSearchExpression();
+ root = processTokens();
} catch (SearchTokenizerException e) {
return null;
}
@@ -46,8 +46,10 @@ public class SearchParser {
return searchOption;
}
- private SearchExpression processSearchExpression() {
+ protected SearchExpression processTokens() {
SearchQueryToken token = nextToken();
+
+
if(token.getToken() == SearchQueryToken.Token.OPEN) {
throw illegalState();
} else if(token.getToken() == SearchQueryToken.Token.NOT) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
index 24b1291..efd7280 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
@@ -20,7 +20,7 @@ package org.apache.olingo.server.core.uri.parser.search;
import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
-public class SearchTermImpl implements SearchTerm {
+public class SearchTermImpl extends SearchExpressionImpl implements SearchTerm {
private final String term;
public SearchTermImpl(String term) {
@@ -34,6 +34,6 @@ public class SearchTermImpl implements SearchTerm {
@Override
public String toString() {
- return "{'" + term + "'}";
+ return "'" + term + "'";
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
index 639540d..51e3a24 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
@@ -22,7 +22,7 @@ import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
import org.apache.olingo.server.api.uri.queryoption.search.SearchUnaryOperatorKind;
-public class SearchUnaryImpl implements SearchUnary {
+public class SearchUnaryImpl extends SearchExpressionImpl implements SearchUnary {
private final SearchTerm operand;
public SearchUnaryImpl(SearchTerm operand) {
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
new file mode 100644
index 0000000..ca9d80b
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import static org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind.AND;
+import static org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind.OR;
+
+import java.lang.reflect.Field;
+
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class SearchParserAndTokenizerTest {
+
+ @Test
+ public void basicParsing() throws SearchTokenizerException {
+ SearchExpressionValidator.init("a")
+ .validate(with("a"));
+ SearchExpressionValidator.init("a AND b")
+ .validate(with("a", and("b")));
+ SearchExpressionValidator.init("a AND b AND c")
+ .validate(with("a", and("b", and("c"))));
+ SearchExpressionValidator.init("a OR b")
+ .validate(with("a", or("b")));
+ SearchExpressionValidator.init("a OR b OR c")
+ .validate(with("a", or("b", or("c"))));
+ }
+
+ @Test
+ @Ignore("Currently not working")
+ public void mixedParsing() throws Exception {
+ SearchExpressionValidator.init("a AND b OR c")
+ .validate(with("c", or("a", and("b"))));
+ }
+
+ @Ignore
+ @Test
+ public void sebuilder() {
+ System.out.println(with("c", or("a", and("b"))).toString());
+ System.out.println(with("a", and("b", and("c"))).toString());
+ System.out.println(with("a").toString());
+ System.out.println(with(not("a")).toString());
+ System.out.println(with("a", and("b")).toString());
+ System.out.println(with("a", or("b")).toString());
+ System.out.println(with("a", and(not("b"))).toString());
+ }
+
+ private static SearchExpression with(String term) {
+ return new SearchTermImpl(term);
+ }
+
+ private static SearchExpression with(String left, SearchExpression right) {
+ setLeftField(left, right);
+ return right;
+ }
+
+ private static SearchUnary with(SearchUnary unary) {
+ return unary;
+ }
+
+ private static SearchExpression or(String left, SearchExpression right) {
+ SearchExpression or = or(right);
+ setLeftField(left, right);
+ return or;
+ }
+
+ private static SearchExpression and(String left, SearchExpression right) {
+ SearchExpression and = and(right);
+ setLeftField(left, right);
+ return and;
+ }
+
+ private static SearchExpression or(SearchExpression right) {
+ return new SearchBinaryImpl(null, OR, right);
+ }
+
+ private static SearchExpression and(SearchExpression right) {
+ return new SearchBinaryImpl(null, AND, right);
+ }
+
+ private static SearchExpression and(String right) {
+ return and(new SearchTermImpl(right));
+ }
+
+ private static SearchExpression or(String right) {
+ return or(new SearchTermImpl(right));
+ }
+
+ private static SearchUnary not(String term) {
+ return new SearchUnaryImpl(new SearchTermImpl(term));
+ }
+
+ private static void setLeftField(String left, SearchExpression se) {
+ try {
+ Field field = null;
+ if (se instanceof SearchUnaryImpl) {
+ field = SearchBinaryImpl.class.getDeclaredField("operand");
+ } else if (se instanceof SearchBinaryImpl) {
+ field = SearchBinaryImpl.class.getDeclaredField("left");
+ } else {
+ Assert.fail("Unexpected exception: " + se.getClass());
+ }
+ field.setAccessible(true);
+ field.set(se, new SearchTermImpl(left));
+ } catch (Exception e) {
+ Assert.fail("Unexpected exception: " + e.getClass());
+ }
+ }
+
+ private static class SearchExpressionValidator {
+ private boolean log;
+ private final String searchQuery;
+
+ private SearchExpressionValidator(String searchQuery) {
+ this.searchQuery = searchQuery;
+ }
+
+ private static SearchExpressionValidator init(String searchQuery) {
+ return new SearchExpressionValidator(searchQuery);
+ }
+
+ private SearchExpressionValidator enableLogging() {
+ log = true;
+ return this;
+ }
+
+ private void validate(Class<? extends Exception> exception) throws SearchTokenizerException {
+ try {
+ new SearchTokenizer().tokenize(searchQuery);
+ } catch (Exception e) {
+ Assert.assertEquals(exception, e.getClass());
+ return;
+ }
+ Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
+ }
+
+ private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException {
+ SearchParser tokenizer = new SearchParser();
+ SearchOption result = tokenizer.parse(null, searchQuery);
+ Assert.assertNotNull(result);
+ final SearchExpression searchExpression = result.getSearchExpression();
+ Assert.assertNotNull(searchExpression);
+ if (log) {
+ System.out.println(expectedSearchExpression);
+ }
+ Assert.assertEquals(expectedSearchExpression.toString(), searchExpression.toString());
+ }
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index fa42293..961663c 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -6,9 +6,9 @@
* 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
- *
+ *
* 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
@@ -18,151 +18,159 @@
*/
package org.apache.olingo.server.core.uri.parser.search;
-import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
-import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
-import org.junit.Assert;
+import org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token;
import org.junit.Ignore;
import org.junit.Test;
-import java.lang.reflect.Field;
-
-import static org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind.*;
-
-public class SearchParserTest {
+public class SearchParserTest extends SearchParser {
@Test
- public void basicParsing() throws SearchTokenizerException {
- SearchExpressionValidator.init("a")
- .validate(with("a"));
- SearchExpressionValidator.init("a AND b")
- .validate(with("a", and("b")));
- SearchExpressionValidator.init("a AND b AND c")
- .validate(with("a", and("b", and("c"))));
- SearchExpressionValidator.init("a OR b")
- .validate(with("a", or("b")));
- SearchExpressionValidator.init("a OR b OR c")
- .validate(with("a", or("b", or("c"))));
+ public void simple() {
+ SearchExpression se = run(Token.WORD);
+ assertEquals("'word1'", se.toString());
+ assertTrue(se.isSearchTerm());
+ assertEquals("word1", se.asSearchTerm().getSearchTerm());
+
+ se = run(Token.PHRASE);
+ assertEquals("'phrase1'", se.toString());
+ assertTrue(se.isSearchTerm());
+ //TODO: Check if quotation marks should be part of the string we deliver
+ assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
}
@Test
- @Ignore("Currently not working")
- public void mixedParsing() throws Exception{
- SearchExpressionValidator.init("a AND b OR c")
- .validate(with("c", or("a", and("b"))));
+ public void simpleAnd() {
+ SearchExpression se = run(Token.WORD, Token.AND, Token.WORD);
+ assertEquals("{'word1' AND 'word2'}", se.toString());
+ assertTrue(se.isSearchBinary());
+ assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
+ assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
+ assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
+
+ se = run(Token.PHRASE, Token.AND, Token.PHRASE);
+ assertEquals("{'phrase1' AND 'phrase2'}", se.toString());
+ assertTrue(se.isSearchBinary());
+ assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
+ assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
+ assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
-
+
@Test
- @Ignore("Internal test, to be deleted")
- public void sebuilder() {
- System.out.println(with("c", or("a", and("b"))).toString());
- System.out.println(with("a", and("b", and("c"))).toString());
- System.out.println(with("a").toString());
- System.out.println(with(not("a")).toString());
- System.out.println(with("a", and("b")).toString());
- System.out.println(with("a", or("b")).toString());
- System.out.println(with("a", and(not("b"))).toString());
- }
-
- private static SearchExpression with(String term) {
- return new SearchTermImpl(term);
- }
-
-
- private static SearchExpression with(String left, SearchExpression right) {
- setLeftField(left, right);
- return right;
+ public void simpleOr() {
+ SearchExpression se = run(Token.WORD, Token.OR, Token.WORD);
+ assertEquals("{'word1' OR 'word2'}", se.toString());
+ assertTrue(se.isSearchBinary());
+ assertEquals(SearchBinaryOperatorKind.OR, se.asSearchBinary().getOperator());
+ assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
+ assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
+
+ se = run(Token.PHRASE, Token.OR, Token.PHRASE);
+ assertEquals("{'phrase1' OR 'phrase2'}", se.toString());
+ assertTrue(se.isSearchBinary());
+ assertEquals(SearchBinaryOperatorKind.OR, se.asSearchBinary().getOperator());
+ assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
+ assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
-
- private static SearchUnary with(SearchUnary unary) {
- return unary;
- }
-
- private static SearchExpression or(String left, SearchExpression right) {
- SearchExpression or = or(right);
- setLeftField(left, right);
- return or;
- }
-
- private static SearchExpression and(String left, SearchExpression right) {
- SearchExpression and = and(right);
- setLeftField(left, right);
- return and;
- }
-
- private static SearchExpression or(SearchExpression right) {
- return new SearchBinaryImpl(null, OR, right);
+
+ @Ignore
+ @Test
+ public void simpleImplicitAnd() {
+ SearchExpression se = run(Token.WORD, Token.WORD);
+ assertEquals("{'word1' AND 'word2'}", se.toString());
+ assertTrue(se.isSearchBinary());
+ assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
+ assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
+ assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
+
+ se = run(Token.PHRASE, Token.PHRASE);
+ assertEquals("{'phrase1' AND 'phrase2'}", se.toString());
+ assertTrue(se.isSearchBinary());
+ assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
+ assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
+ assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
-
- private static SearchExpression and(SearchExpression right) {
- return new SearchBinaryImpl(null, AND, right);
+
+ @Ignore
+ @Test
+ public void simpleBrackets() {
+ SearchExpression se = run(Token.OPEN, Token.WORD, Token.CLOSE);
+ assertEquals("'word1'", se.toString());
+ assertTrue(se.isSearchTerm());
+ assertEquals("word1", se.asSearchTerm().getSearchTerm());
+
+ se = run(Token.OPEN, Token.PHRASE, Token.CLOSE);
+ assertEquals("'phrase1'", se.toString());
+ assertTrue(se.isSearchTerm());
+ assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
}
-
- private static SearchExpression and(String right) {
- return and(new SearchTermImpl(right));
+
+ @Ignore
+ @Test
+ public void simpleNot() {
+ SearchExpression se = run(Token.NOT, Token.WORD);
+ assertEquals("{NOT 'word1'}", se.toString());
+ assertTrue(se.isSearchUnary());
+ assertEquals("word1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
+
+ se = run(Token.NOT, Token.WORD);
+ assertEquals("'phrase1'", se.toString());
+ assertTrue(se.isSearchUnary());
+ assertEquals("phrase1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
}
-
- private static SearchExpression or(String right) {
- return or(new SearchTermImpl(right));
+
+ @Ignore
+ @Test
+ public void precedenceLast() {
+ //word1 AND (word2 AND word3)
+ SearchExpression se = run(Token.WORD, Token.AND, Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE);
+ assertEquals("{'word1' AND {'word2' AND 'word3'}}", se.toString());
}
-
- private static SearchUnary not(String term) {
- return new SearchUnaryImpl(new SearchTermImpl(term));
+
+ @Ignore
+ @Test
+ public void precedenceFirst() {
+ //(word1 AND word2) AND word3
+ SearchExpression se = run(Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE, Token.AND, Token.WORD);
+ assertEquals("{{'word1' AND 'word2'} AND 'word3'}", se.toString());
}
-
- private static void setLeftField(String left, SearchExpression se) {
- try {
- Field field = null;
- if(se instanceof SearchUnaryImpl) {
- field = SearchBinaryImpl.class.getDeclaredField("operand");
- } else if(se instanceof SearchBinaryImpl) {
- field = SearchBinaryImpl.class.getDeclaredField("left");
- } else {
- Assert.fail("Unexpected exception: " + se.getClass());
- }
- field.setAccessible(true);
- field.set(se, new SearchTermImpl(left));
- } catch (Exception e) {
- Assert.fail("Unexpected exception: " + e.getClass());
- }
+
+
+ private SearchExpression run(SearchQueryToken.Token... tokenArray) {
+ List<SearchQueryToken> tokenList = prepareTokens(tokenArray);
+ tokens = tokenList.iterator();
+ SearchExpression se = processTokens();
+ assertNotNull(se);
+ return se;
}
- private static class SearchExpressionValidator {
- private boolean log;
- private final String searchQuery;
-
- private SearchExpressionValidator(String searchQuery) {
- this.searchQuery = searchQuery;
- }
-
- private static SearchExpressionValidator init(String searchQuery) {
- return new SearchExpressionValidator(searchQuery);
- }
- private SearchExpressionValidator enableLogging() {
- log = true;
- return this;
- }
- private void validate(Class<? extends Exception> exception) throws SearchTokenizerException {
- try {
- new SearchTokenizer().tokenize(searchQuery);
- } catch (Exception e) {
- Assert.assertEquals(exception, e.getClass());
- return;
- }
- Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
- }
-
- private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException {
- SearchParser tokenizer = new SearchParser();
- SearchOption result = tokenizer.parse(null, searchQuery);
- Assert.assertNotNull(result);
- final SearchExpression searchExpression = result.getSearchExpression();
- Assert.assertNotNull(searchExpression);
- if(log) {
- System.out.println(expectedSearchExpression);
+ public List<SearchQueryToken> prepareTokens(SearchQueryToken.Token... tokenArray) {
+ ArrayList<SearchQueryToken> tokenList = new ArrayList<SearchQueryToken>();
+ int wordNumber = 1;
+ int phraseNumber = 1;
+ for (int i = 0; i < tokenArray.length; i++) {
+ SearchQueryToken token = mock(SearchQueryToken.class);
+ when(token.getToken()).thenReturn(tokenArray[i]);
+ if (tokenArray[i] == Token.WORD) {
+ when(token.getLiteral()).thenReturn("word" + wordNumber);
+ wordNumber++;
+ } else if (tokenArray[i] == Token.PHRASE) {
+ when(token.getLiteral()).thenReturn("phrase" + phraseNumber);
+ phraseNumber++;
}
- Assert.assertEquals(expectedSearchExpression.toString(), searchExpression.toString());
+ tokenList.add(token);
}
+ return tokenList;
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/22d152fc/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 828b4c4..904bd3f 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -33,7 +33,7 @@ public class SearchTokenizerTest {
public void parseBasics() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
-
+
//
result = tokenizer.tokenize("abc");
Assert.assertNotNull(result);
[20/23] olingo-odata4 git commit: [OLINGO-568] Merge branch 'master'
into OLINGO-568_SearchParser_Draft
Posted by mi...@apache.org.
[OLINGO-568] Merge branch 'master' into OLINGO-568_SearchParser_Draft
arser_Draft
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/c0adc020
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/c0adc020
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/c0adc020
Branch: refs/heads/master
Commit: c0adc020b22ed728aaed1659fc8485e4c214141f
Parents: 9ff30e7 6614aea
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Nov 17 10:50:06 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Nov 17 10:50:06 2015 +0100
----------------------------------------------------------------------
.../commons/core/edm/EdmEnumTypeImpl.java | 47 ++++++--
.../server/core/edm/provider/EdmEnumTest.java | 16 ++-
.../core/uri/parser/UriParseTreeVisitor.java | 18 ++-
.../TechnicalPrimitiveComplexProcessor.java | 8 +-
.../expression/ExpressionVisitorImpl.java | 9 +-
.../expression/operand/UntypedOperand.java | 19 +---
.../queryoptions/options/FilterHandler.java | 2 +-
.../queryoptions/options/OrderByHandler.java | 4 +-
.../core/uri/antlr/TestFullResourcePath.java | 113 +++++++++++++++----
9 files changed, 170 insertions(+), 66 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c0adc020/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
[14/23] olingo-odata4 git commit: [OLINGO-568] Refactored
SearchParser for further development
Posted by mi...@apache.org.
[OLINGO-568] Refactored SearchParser for further development
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/40962a9a
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/40962a9a
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/40962a9a
Branch: refs/heads/master
Commit: 40962a9a18259a19410e22ee2573c1816b7a5cbc
Parents: a8d63fb
Author: mibo <mi...@apache.org>
Authored: Thu Nov 12 23:08:35 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Thu Nov 12 23:08:35 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchParser.java | 125 +++++++++++--------
.../core/uri/parser/search/SearchTokenizer.java | 2 +-
.../search/SearchParserAndTokenizerTest.java | 24 +++-
.../uri/parser/search/SearchParserTest.java | 15 ++-
4 files changed, 103 insertions(+), 63 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/40962a9a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index 5e26c35..25c52f2 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -21,23 +21,23 @@ package org.apache.olingo.server.core.uri.parser.search;
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
-import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
import java.util.Iterator;
+import java.util.List;
public class SearchParser {
- protected Iterator<SearchQueryToken> tokens;
- protected SearchExpression root;
-// private SearchQueryToken currentToken;
+ private Iterator<SearchQueryToken> tokens;
+ private SearchExpression root;
+ private SearchQueryToken token;
public SearchOption parse(String path, String value) {
SearchTokenizer tokenizer = new SearchTokenizer();
try {
tokens = tokenizer.tokenize(value).iterator();
-// currentToken = tokens.next();
- root = processTokens();
+ nextToken();
+ root = processSearchExpression(null);
} catch (SearchTokenizerException e) {
return null;
}
@@ -46,81 +46,98 @@ public class SearchParser {
return searchOption;
}
- protected SearchExpression processTokens() {
- SearchQueryToken token = nextToken();
-
-
+ protected SearchExpression parseInternal(List<SearchQueryToken> tokens) {
+ this.tokens = tokens.iterator();
+ nextToken();
+ return processSearchExpression(null);
+ }
+
+ private SearchExpression processSearchExpression(SearchExpression left) {
+ if(token == null) {
+ return left;
+ }
+
if(token.getToken() == SearchQueryToken.Token.OPEN) {
+ processOpen();
throw illegalState();
+ } else if(token.getToken() == SearchQueryToken.Token.CLOSE) {
+ processClose();
+ throw illegalState();
} else if(token.getToken() == SearchQueryToken.Token.NOT) {
- return processNot();
+ processNot();
} else if(token.getToken() == SearchQueryToken.Token.PHRASE ||
token.getToken() == SearchQueryToken.Token.WORD) {
- return processTerm(token);
-// } else if(token.getToken() == SearchQueryToken.Token.AND) {
-// return processAnd();
+ return processSearchExpression(processTerm());
+ } else if(token.getToken() == SearchQueryToken.Token.AND) {
+ SearchExpression se = processAnd(left);
+ return processSearchExpression(se);
+ } else if(token.getToken() == SearchQueryToken.Token.OR) {
+ return processOr(left);
} else {
throw illegalState();
}
+ throw illegalState();
}
- private SearchExpression processAnd(SearchExpression se) {
- SearchQueryToken token = nextToken();
- if(token.getToken() == SearchQueryToken.Token.PHRASE ||
- token.getToken() == SearchQueryToken.Token.WORD) {
-// SearchExpression t = processTerm(token);
- return new SearchBinaryImpl(se, SearchBinaryOperatorKind.AND, processTerm(token));
- }
- throw illegalState();
+ private void processClose() {
+ nextToken();
}
- private SearchExpression processOr(SearchExpression se) {
- SearchQueryToken token = nextToken();
- if(token.getToken() == SearchQueryToken.Token.PHRASE ||
- token.getToken() == SearchQueryToken.Token.WORD) {
- return new SearchBinaryImpl(se, SearchBinaryOperatorKind.OR, processTerm(token));
- }
- throw illegalState();
+ private void processOpen() {
+ nextToken();
+ }
+
+ private SearchExpression processAnd(SearchExpression left) {
+ nextToken();
+ SearchExpression se = processTerm();
+ return new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, se);
+ }
+
+ public SearchExpression processOr(SearchExpression left) {
+ nextToken();
+ SearchExpression se = processSearchExpression(left);
+ return new SearchBinaryImpl(left, SearchBinaryOperatorKind.OR, se);
}
private RuntimeException illegalState() {
return new RuntimeException();
}
- private SearchUnaryImpl processNot() {
- SearchQueryToken token = nextToken();
- if(token.getToken() == SearchQueryToken.Token.PHRASE ||
- token.getToken() == SearchQueryToken.Token.WORD) {
- throw illegalState();
-// return new SearchUnaryImpl(processTerm(token));
- }
- throw illegalState();
+ private void processNot() {
+ nextToken();
}
- private SearchQueryToken nextToken() {
-// if(tokens.hasNext()) {
- return tokens.next();
-// }
+ private void nextToken() {
+ if(tokens.hasNext()) {
+ token = tokens.next();
+ } else {
+ token = null;
+ }
// return null;
}
- private SearchExpression processTerm(SearchQueryToken token) {
- SearchTerm searchTerm = new SearchTermImpl(token.getLiteral());
- if(isEof()) {
- return searchTerm;
+ private SearchExpression processTerm() {
+ if(token.getToken() == SearchQueryToken.Token.NOT) {
+ return new SearchUnaryImpl(processPhrase());
}
-
- SearchQueryToken next = nextToken();
- if(next.getToken() == SearchQueryToken.Token.AND) {
- return processAnd(searchTerm);
- } else if(next.getToken() == SearchQueryToken.Token.OR) {
- return processOr(searchTerm);
+ if(token.getToken() == SearchQueryToken.Token.PHRASE) {
+ return processPhrase();
}
+ if(token.getToken() == SearchQueryToken.Token.WORD) {
+ return processWord();
+ }
+ return null;
+ }
- throw illegalState();
+ private SearchTermImpl processWord() {
+ String literal = token.getLiteral();
+ nextToken();
+ return new SearchTermImpl(literal);
}
- private boolean isEof() {
- return !tokens.hasNext();
+ private SearchTermImpl processPhrase() {
+ String literal = token.getLiteral();
+ nextToken();
+ return new SearchTermImpl(literal);
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/40962a9a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 9288981..a9a5895 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -442,7 +442,7 @@ public class SearchTokenizer {
*/
public List<SearchQueryToken> tokenize(final String searchQuery)
throws SearchTokenizerException {
-
+
char[] chars = searchQuery.trim().toCharArray();
State state = new SearchExpressionState();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/40962a9a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index 43b63c3..3ecd517 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -34,12 +34,15 @@ public class SearchParserAndTokenizerTest {
@Test
public void basicParsing() throws SearchTokenizerException {
+// SearchExpressionValidator.init("a AND b OR c").enableLogging()
+// .validate(with("a"));
+
SearchExpressionValidator.init("a")
.validate(with("a"));
SearchExpressionValidator.init("a AND b")
.validate(with("a", and("b")));
SearchExpressionValidator.init("a AND b AND c")
- .validate(with("a", and("b", and("c"))));
+ .validate("{{'a' AND 'b'} AND 'c'}");
SearchExpressionValidator.init("a OR b")
.validate(with("a", or("b")));
SearchExpressionValidator.init("a OR b OR c")
@@ -47,10 +50,11 @@ public class SearchParserAndTokenizerTest {
}
@Test
- @Ignore("Currently not working")
public void mixedParsing() throws Exception {
SearchExpressionValidator.init("a AND b OR c")
- .validate(with("c", or("a", and("b"))));
+ .validate("{{'a' AND 'b'} OR 'c'}");
+ SearchExpressionValidator.init("a OR b AND c")
+ .validate("{'a' OR {'b' AND 'c'}}");
}
@Ignore
@@ -156,15 +160,25 @@ public class SearchParserAndTokenizerTest {
}
private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException {
+ final SearchExpression searchExpression = getSearchExpression();
+ Assert.assertEquals(expectedSearchExpression.toString(), searchExpression.toString());
+ }
+
+ private void validate(String expectedSearchExpression) throws SearchTokenizerException {
+ final SearchExpression searchExpression = getSearchExpression();
+ Assert.assertEquals(expectedSearchExpression, searchExpression.toString());
+ }
+
+ private SearchExpression getSearchExpression() {
SearchParser tokenizer = new SearchParser();
SearchOption result = tokenizer.parse(null, searchQuery);
Assert.assertNotNull(result);
final SearchExpression searchExpression = result.getSearchExpression();
Assert.assertNotNull(searchExpression);
if (log) {
- System.out.println(expectedSearchExpression);
+ System.out.println(searchExpression);
}
- Assert.assertEquals(expectedSearchExpression.toString(), searchExpression.toString());
+ return searchExpression;
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/40962a9a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 961663c..ce37f3d 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -144,12 +144,21 @@ public class SearchParserTest extends SearchParser {
SearchExpression se = run(Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE, Token.AND, Token.WORD);
assertEquals("{{'word1' AND 'word2'} AND 'word3'}", se.toString());
}
-
+
+ @Test
+ public void combinationAndOr() {
+ //word1 AND word2 OR word3
+ SearchExpression se = run(Token.WORD, Token.AND, Token.WORD, Token.OR, Token.WORD);
+ assertEquals("{{'word1' AND 'word2'} OR 'word3'}", se.toString());
+ //word1 OR word2 AND word3
+ se = run(Token.WORD, Token.OR, Token.WORD, Token.AND, Token.WORD);
+ assertEquals("{'word1' OR {'word2' AND 'word3'}}", se.toString());
+ }
+
private SearchExpression run(SearchQueryToken.Token... tokenArray) {
List<SearchQueryToken> tokenList = prepareTokens(tokenArray);
- tokens = tokenList.iterator();
- SearchExpression se = processTokens();
+ SearchExpression se = parseInternal(tokenList);
assertNotNull(se);
return se;
}
[05/23] olingo-odata4 git commit: [OLINGO-568] Code clean up
Posted by mi...@apache.org.
[OLINGO-568] Code clean up
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/b3bbfa6f
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/b3bbfa6f
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/b3bbfa6f
Branch: refs/heads/master
Commit: b3bbfa6fe154d91a5f58328acc8816bd81af798a
Parents: bbdd0d7
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Nov 9 13:29:32 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Nov 9 13:29:32 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchTokenizer.java | 69 +++++++++++---------
.../uri/parser/search/SearchTokenizerTest.java | 21 ++++--
2 files changed, 54 insertions(+), 36 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b3bbfa6f/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index e058a00..67d4655 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -39,16 +39,21 @@ import java.util.List;
* </code>
*/
public class SearchTokenizer {
- public static final char QUOTATION_MARK = '\"';
- //RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
- //BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
-
private static abstract class State implements SearchQueryToken {
private Token token = null;
private boolean finished = false;
- public static final char EOF = 0x03;
+ protected static final char EOF = 0x03;
+ protected static final char QUOTATION_MARK = '\"';
+ protected static final char CHAR_N = 'N';
+ protected static final char CHAR_O = 'O';
+ protected static final char CHAR_T = 'T';
+ protected static final char CHAR_A = 'A';
+ protected static final char CHAR_D = 'D';
+ protected static final char CHAR_R = 'R';
+ protected static final char CHAR_CLOSE = ')';
+ protected static final char CHAR_OPEN = '(';
public State(Token t) {
token = t;
@@ -79,7 +84,7 @@ public class SearchTokenizer {
static boolean isAllowedChar(final char character) {
// TODO mibo: add missing allowed characters
- return 'A' <= character && character <= 'Z' // case A..Z
+ return CHAR_A <= character && character <= 'Z' // case A..Z
|| 'a' <= character && character <= 'z' // case a..z
|| '0' <= character && character <= '9'; // case 0..9
}
@@ -109,6 +114,8 @@ public class SearchTokenizer {
return character == EOF;
}
+ //BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
+ //RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
static boolean isWhitespace(final char character) {
//( SP / HTAB / "%20" / "%09" )
// TODO mibo: add missing whitespaces
@@ -163,11 +170,11 @@ public class SearchTokenizer {
}
@Override
public State nextChar(char c) {
- if (c == '(') {
+ if (c == CHAR_OPEN) {
return new OpenState();
} else if (isWhitespace(c)) {
return new RwsState();
- } else if(c == ')') {
+ } else if(c == CHAR_CLOSE) {
return new CloseState();
} else if(isEof(c)) {
return finish();
@@ -190,7 +197,7 @@ public class SearchTokenizer {
}
@Override
public State nextChar(char c) {
- if(c == 'n' || c == 'N') {
+ if(c == CHAR_N) {
return new NotState(c);
} else if (c == QUOTATION_MARK) {
return new SearchPhraseState(c);
@@ -217,7 +224,7 @@ public class SearchTokenizer {
public State nextChar(char c) {
if (isAllowedChar(c)) {
return allowed(c);
- } else if (c == ')') {
+ } else if (c == CHAR_CLOSE) {
finish();
return new CloseState();
} else if (isWhitespace(c)) {
@@ -226,7 +233,7 @@ public class SearchTokenizer {
} else if (isEof(c)) {
return finish();
}
- throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ return forbidden(c);
}
}
@@ -255,7 +262,7 @@ public class SearchTokenizer {
} else if (isEof(c)) {
return finish();
}
- throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ return forbidden(c);
}
}
@@ -268,7 +275,7 @@ public class SearchTokenizer {
public State nextChar(char c) {
finish();
if (isWhitespace(c)) {
- throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ return forbidden(c);
}
return new SearchExpressionState().init(c);
}
@@ -293,12 +300,15 @@ public class SearchTokenizer {
private class NotState extends LiteralState {
public NotState(char c) {
super(Token.NOT, c);
+ if(c != CHAR_N) {
+ forbidden(c);
+ }
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && (c == 'o' || c == 'O')) {
+ if (getLiteral().length() == 1 && (c == CHAR_O)) {
return allowed(c);
- } else if (getLiteral().length() == 2 && (c == 't' || c == 'T')) {
+ } else if (getLiteral().length() == 2 && (c == CHAR_T)) {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
@@ -328,15 +338,15 @@ public class SearchTokenizer {
private class AndState extends LiteralState {
public AndState(char c) {
super(Token.AND, c);
- if(c != 'a' && c != 'A') {
+ if(c != CHAR_A) {
forbidden(c);
}
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && (c == 'n' || c == 'N')) {
+ if (getLiteral().length() == 1 && (c == CHAR_N)) {
return allowed(c);
- } else if (getLiteral().length() == 2 && (c == 'd' || c == 'D')) {
+ } else if (getLiteral().length() == 2 && (c == CHAR_D)) {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
@@ -350,13 +360,13 @@ public class SearchTokenizer {
private class OrState extends LiteralState {
public OrState(char c) {
super(Token.OR, c);
- if(c != 'o' && c != 'O') {
+ if(c != CHAR_O) {
forbidden(c);
}
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && (c == 'r' || c == 'R')) {
+ if (getLiteral().length() == 1 && (c == CHAR_R)) {
return allowed(c);
} else if(getLiteral().length() == 2 && isWhitespace(c)) {
finish();
@@ -367,6 +377,7 @@ public class SearchTokenizer {
}
}
+ // RWS 'OR' RWS searchExpr
// RWS [ 'AND' RWS ] searchExpr
private class BeforeSearchExpressionRwsState extends State {
public BeforeSearchExpressionRwsState() {
@@ -382,7 +393,6 @@ public class SearchTokenizer {
}
}
-
private class RwsState extends State {
public RwsState() {
super(Token.RWS);
@@ -391,9 +401,9 @@ public class SearchTokenizer {
public State nextChar(char c) {
if (isWhitespace(c)) {
return allowed(c);
- } else if (c == 'O' || c == 'o') {
+ } else if (c == CHAR_O) {
return new OrState(c);
- } else if (c == 'A' || c == 'a') {
+ } else if (c == CHAR_A) {
return new AndState(c);
} else {
return new ImplicitAndState(c);
@@ -407,15 +417,15 @@ public class SearchTokenizer {
State state = new SearchExpressionState();
List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
- State lastAddedToken = null;
+ State lastAdded = null;
for (char aChar : chars) {
State next = state.nextChar(aChar);
if (next instanceof ImplicitAndState) {
- lastAddedToken = next;
+ lastAdded = next;
states.add(next);
next = ((ImplicitAndState)next).nextState();
- } else if (state.isFinished() && state != lastAddedToken) {
- lastAddedToken = state;
+ } else if (state.isFinished() && state != lastAdded) {
+ lastAdded = state;
states.add(state);
}
state = next;
@@ -423,9 +433,8 @@ public class SearchTokenizer {
final State lastState = state.nextChar(State.EOF);
if(lastState.isFinished()) {
- states.add(state);
- if(state.getToken() != lastState.getToken()) {
- states.add(lastState);
+ if(state != lastAdded) {
+ states.add(state);
}
} else {
throw new IllegalStateException("State: " + state + " not finished and list is: " + states.toString());
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b3bbfa6f/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index ceae8d8..9044282 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -32,7 +32,7 @@ public class SearchTokenizerTest {
private boolean logEnabled = false;
@Test
- public void testParse() throws Exception {
+ public void parseBasics() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
@@ -105,10 +105,12 @@ public class SearchTokenizerTest {
log(result.toString());
Assert.assertEquals(PHRASE, result.get(0).getToken());
Assert.assertEquals("\"99_88.\"", result.get(0).getLiteral());
+
+ SearchValidator.init("abc or \"xyz\"").addExpected(WORD, AND, WORD, AND, PHRASE).validate();
}
@Test
- public void testParseNot() throws Exception {
+ public void parseNot() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
@@ -117,10 +119,12 @@ public class SearchTokenizerTest {
log(result.toString());
Assert.assertEquals(NOT, result.get(0).getToken());
Assert.assertEquals(WORD, result.get(1).getToken());
+
+ SearchValidator.init("not abc").addExpected(WORD, AND, WORD).validate();
}
@Test
- public void testParseOr() throws Exception {
+ public void parseOr() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
@@ -139,6 +143,8 @@ public class SearchTokenizerTest {
Assert.assertEquals(WORD, result.get(2).getToken());
Assert.assertEquals(OR, result.get(3).getToken());
Assert.assertEquals(WORD, result.get(4).getToken());
+
+ SearchValidator.init("abc or xyz").addExpected(WORD, AND, WORD, AND, WORD).validate();
}
@Test
@@ -151,7 +157,7 @@ public class SearchTokenizerTest {
}
@Test
- public void testParseAnd() throws Exception {
+ public void parseAnd() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
@@ -165,10 +171,13 @@ public class SearchTokenizerTest {
// no lower case allowed for AND
result = tokenizer.tokenize("abc and xyz");
Assert.assertNotNull(result);
+ Assert.assertEquals(5, result.size());
log(result.toString());
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
+ Assert.assertEquals(AND, result.get(3).getToken());
+ Assert.assertEquals(WORD, result.get(4).getToken());
// implicit AND
result = tokenizer.tokenize("abc xyz");
@@ -199,7 +208,7 @@ public class SearchTokenizerTest {
}
@Test
- public void testParseAndOr() throws Exception {
+ public void parseAndOr() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
@@ -321,7 +330,7 @@ public class SearchTokenizerTest {
validate("abc AND (def OR ghi)");
validate("abc AND (def ghi)");
}
-
+
public boolean validate(String query) {
return new SearchValidator(query).validate();
}
[18/23] olingo-odata4 git commit: [OLINGO-568] Enabled serch option
in TevSvc
Posted by mi...@apache.org.
[OLINGO-568] Enabled serch option in TevSvc
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/21e115b6
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/21e115b6
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/21e115b6
Branch: refs/heads/master
Commit: 21e115b6bf91c608c31b1584da83e353664ebdca
Parents: 7d4944d
Author: mibo <mi...@apache.org>
Authored: Mon Nov 16 23:00:18 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Mon Nov 16 23:06:29 2015 +0100
----------------------------------------------------------------------
.../processor/TechnicalEntityProcessor.java | 2 +
.../tecsvc/processor/TechnicalProcessor.java | 3 +-
.../queryoptions/options/SearchHandler.java | 92 ++++++++++++++++++++
3 files changed, 95 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/21e115b6/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 74cdd51..923bf29 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@ -67,6 +67,7 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.ExpandSystemQueryO
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.CountHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.FilterHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.OrderByHandler;
+import org.apache.olingo.server.tecsvc.processor.queryoptions.options.SearchHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.ServerSidePagingHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.SkipHandler;
import org.apache.olingo.server.tecsvc.processor.queryoptions.options.TopHandler;
@@ -486,6 +487,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
OrderByHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, uriInfo, serviceMetadata.getEdm());
SkipHandler.applySkipSystemQueryHandler(uriInfo.getSkipOption(), entitySet);
TopHandler.applyTopSystemQueryOption(uriInfo.getTopOption(), entitySet);
+ SearchHandler.applySearchSystemQueryOption(uriInfo.getSearchOption(), entitySet);
final Integer pageSize = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getMaxPageSize();
final Integer serverPageSize = ServerSidePagingHandler.applyServerSidePaging(uriInfo.getSkipTokenOption(),
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/21e115b6/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index b63bdd8..28cf63d 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -233,8 +233,7 @@ public abstract class TechnicalProcessor implements Processor {
}
protected void validateOptions(final UriInfoResource uriInfo) throws ODataApplicationException {
- if (uriInfo.getIdOption() != null
- || uriInfo.getSearchOption() != null) {
+ if (uriInfo.getIdOption() != null) {
throw new ODataApplicationException("Not all of the specified options are supported.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/21e115b6/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
new file mode 100644
index 0000000..5ce4530
--- /dev/null
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
@@ -0,0 +1,92 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.tecsvc.processor.queryoptions.options;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinary;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+public class SearchHandler {
+ public static void applySearchSystemQueryOption(final SearchOption searchOption, final EntityCollection entitySet)
+ throws ODataApplicationException {
+
+ if (searchOption != null) {
+ Iterator<Entity> it = entitySet.getEntities().iterator();
+ while(it.hasNext()) {
+ boolean keep = false;
+ Entity next = it.next();
+ List<Property> propertyList = next.getProperties();
+ for (Property property : propertyList) {
+ SearchExpression se = searchOption.getSearchExpression();
+ if(isTrue(se, property)) {
+ keep = true;
+ break;
+ }
+ }
+ if(!keep) {
+ it.remove();
+ }
+ }
+ }
+ }
+
+ private static boolean isTrue(SearchTerm term, Property property) {
+ if(property.isPrimitive()) {
+ String propertyString = property.asPrimitive().toString();
+ return propertyString != null && propertyString.contains(term.getSearchTerm());
+ }
+ return false;
+ }
+
+ private static boolean isTrue(SearchBinary binary, Property property) throws ODataApplicationException {
+ SearchExpression left = binary.getLeftOperand();
+ SearchExpression right = binary.getRightOperand();
+ if(binary.getOperator() == SearchBinaryOperatorKind.AND) {
+ return isTrue(left, property) && isTrue(right, property);
+ } else if(binary.getOperator() == SearchBinaryOperatorKind.OR) {
+ return isTrue(left, property) || isTrue(right, property);
+ } else {
+ throw new ODataApplicationException("Found unknown SearchBinaryOperatorKind: " + binary.getOperator(),
+ HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
+ }
+ }
+
+ private static boolean isTrue(SearchExpression searchExpression, Property property) throws ODataApplicationException {
+ if(searchExpression.isSearchBinary()) {
+ return isTrue(searchExpression.asSearchBinary(), property);
+ } else if(searchExpression.isSearchTerm()) {
+ return isTrue(searchExpression.asSearchTerm(), property);
+ } else if(searchExpression.isSearchUnary()) {
+ return !isTrue(searchExpression.asSearchUnary().getOperand(), property);
+ }
+ throw new ODataApplicationException("Found unknown SearchExpression: " + searchExpression,
+ HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
+ }
+}
[21/23] olingo-odata4 git commit: [OLINGO-568] Minor code and
character validation improvements
Posted by mi...@apache.org.
[OLINGO-568] Minor code and character validation improvements
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/6235f3a4
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/6235f3a4
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/6235f3a4
Branch: refs/heads/master
Commit: 6235f3a4434545d6db1026f2b40698b5296f1944
Parents: c0adc02
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Nov 17 15:29:01 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Nov 17 15:29:01 2015 +0100
----------------------------------------------------------------------
.../olingo/server/core/uri/parser/Parser.java | 2 +-
.../core/uri/parser/search/SearchParser.java | 13 +--
.../uri/parser/search/SearchQueryToken.java | 2 +-
.../core/uri/parser/search/SearchTokenizer.java | 117 ++++++++++++++++---
.../search/SearchParserAndTokenizerTest.java | 3 +-
.../uri/parser/search/SearchParserTest.java | 4 +-
.../uri/parser/search/SearchTokenizerTest.java | 34 ++++++
7 files changed, 146 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index 82094cf..d6cb557 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@ -217,7 +217,7 @@ public class Parser {
systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
} else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
SearchParser searchParser = new SearchParser();
- systemOption = searchParser.parse(path, option.value);
+ systemOption = searchParser.parse(option.value);
} else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
SelectEOFContext ctxSelectEOF =
(SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index 804ca67..a9fe332 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -33,11 +33,11 @@ public class SearchParser {
private Iterator<SearchQueryToken> tokens;
private SearchQueryToken token;
- public SearchOption parse(String path, String value) throws SearchParserException, SearchTokenizerException {
+ public SearchOption parse(String searchQuery) throws SearchParserException, SearchTokenizerException {
SearchTokenizer tokenizer = new SearchTokenizer();
SearchExpression searchExpression;
try {
- searchExpression = parseInternal(tokenizer.tokenize(value));
+ searchExpression = parse(tokenizer.tokenize(searchQuery));
} catch (SearchTokenizerException e) {
return null;
}
@@ -46,7 +46,7 @@ public class SearchParser {
return searchOption;
}
- protected SearchExpression parseInternal(List<SearchQueryToken> tokens) throws SearchParserException {
+ protected SearchExpression parse(List<SearchQueryToken> tokens) throws SearchParserException {
this.tokens = tokens.iterator();
nextToken();
if (token == null) {
@@ -101,10 +101,7 @@ public class SearchParser {
}
private boolean isToken(SearchQueryToken.Token toCheckToken) {
- if (token == null) {
- return false;
- }
- return token.getToken() == toCheckToken;
+ return token != null && token.getToken() == toCheckToken;
}
private void validateToken(SearchQueryToken.Token toValidateToken) throws SearchParserException {
@@ -194,6 +191,6 @@ public class SearchParser {
private SearchTerm processPhrase() {
String literal = token.getLiteral();
nextToken();
- return new SearchTermImpl(literal);
+ return new SearchTermImpl(literal.substring(1,literal.length()-1));
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
index eb1a009..3fb66f1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
@@ -19,7 +19,7 @@
package org.apache.olingo.server.core.uri.parser.search;
public interface SearchQueryToken {
- enum Token {OPEN, TERM, NOT, AND, OR, WORD, PHRASE, CLOSE}
+ enum Token {OPEN, NOT, AND, OR, WORD, PHRASE, CLOSE}
Token getToken();
String getLiteral();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 1e3b2ef..fb0ad94 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -98,16 +98,22 @@ public class SearchTokenizer {
}
/**
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
+ * searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
+ *
+ * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
+ *
* qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
+ *
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ *
+ * escape = "\" / "%5C" ; reverse solidus U+005C
+ *
* pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
* / "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
* / "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
*
- * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
+ * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
*
- * escape = "\" / "%5C" ; reverse solidus U+005C
* quotation-mark = DQUOTE / "%22"
*
* ALPHA = %x41-5A / %x61-7A
@@ -119,19 +125,100 @@ public class SearchTokenizer {
*/
static boolean isAllowedPhrase(final char character) {
// FIXME mibo: check missing
+ return isQCharUnescaped(character) || isEscaped(character);
+ }
+
+ /**
+ * escape = "\" / "%5C" ; reverse solidus U+005C
+ * @param character which is checked
+ * @return true if character is allowed
+ */
+ private static boolean isEscaped(char character) {
+ // TODO: mibo(151117): check how to implement
+ return false;
+ }
+
+ /**
+ * qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
+ * @param character which is checked
+ * @return true if character is allowed
+ */
+ private static boolean isQCharUnescaped(char character) {
+ return isUnreserved(character)
+ || isPctEncodedUnescaped(character)
+ || isOtherDelims(character)
+ || character == ':'
+ || character == '@'
+ || character == '/'
+ || character == '$'
+ || character == '\''
+ || character == '=';
+ }
+
+ /**
+ * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
+ * @param character which is checked
+ * @return true if character is allowed
+ */
+ private static boolean isOtherDelims(char character) {
+ return character == '!'
+ || character == '('
+ || character == ')'
+ || character == '*'
+ || character == '+'
+ || character == ','
+ || character == ';';
+ }
+
+ /**
+ * pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
+ * / "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
+ * / "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
+ *
+ * HEXDIG = DIGIT / A-to-F
+ *
+ * @param character which is checked
+ * @return true if character is allowed
+ */
+ private static boolean isPctEncodedUnescaped(char character) {
+ String hex = Integer.toHexString((int) character);
+ char aschar[] = hex.toCharArray();
+ if(aschar[0] == '%') {
+ if(aschar[1] == '2') {
+ return aschar[2] != '2' && isHexDigit(aschar[2]);
+ } else if(aschar[1] == '5') {
+ return aschar[2] != 'C' && isHexDigit(aschar[2]);
+ } else if(isHexDigit(aschar[1])) {
+ return isHexDigit(aschar[2]);
+ }
+ }
+ return false;
+ }
+
+ private static boolean isHexDigit(char character) {
+ return 'A' <= character && character <= 'F' // case A..F
+ || '0' <= character && character <= '9'; // case 0..9
+ }
+
+ /**
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * @param character which is checked
+ * @return true if character is allowed
+ */
+ private static boolean isUnreserved(char character) {
return isAlphaOrDigit(character)
- || character == '-'
- || character == '.'
- || character == '_'
- || character == '~'
- || character == ':'
- || character == '@'
- || character == '/'
- || character == '$'
- || character == '\''
- || character == '=';
+ || character == '-'
+ || character == '.'
+ || character == '_'
+ || character == '~';
}
+ /**
+ * ALPHA = %x41-5A / %x61-7A
+ * DIGIT = %x30-39
+ * @param character which is checked
+ * @return true if character is allowed
+ */
private static boolean isAlphaOrDigit(char character) {
return 'A' <= character && character <= 'Z' // case A..Z
|| 'a' <= character && character <= 'z' // case a..z
@@ -220,7 +307,7 @@ public class SearchTokenizer {
private class SearchTermState extends LiteralState {
public SearchTermState() {
- super(Token.TERM);
+ super(null);
}
@Override
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index dd5ab70..23cac8e 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -185,7 +185,7 @@ public class SearchParserAndTokenizerTest {
private SearchExpression getSearchExpression() throws SearchParserException, SearchTokenizerException {
SearchParser tokenizer = new SearchParser();
- SearchOption result = tokenizer.parse(null, searchQuery);
+ SearchOption result = tokenizer.parse(searchQuery);
Assert.assertNotNull(result);
final SearchExpression searchExpression = result.getSearchExpression();
Assert.assertNotNull(searchExpression);
@@ -195,5 +195,4 @@ public class SearchParserAndTokenizerTest {
return searchExpression;
}
}
-
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 97e941c..ee10e1a 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -220,7 +220,7 @@ public class SearchParserTest extends SearchParser {
private SearchExpression run(SearchQueryToken.Token... tokenArray) throws SearchParserException {
List<SearchQueryToken> tokenList = prepareTokens(tokenArray);
- SearchExpression se = parseInternal(tokenList);
+ SearchExpression se = parse(tokenList);
assertNotNull(se);
return se;
}
@@ -236,7 +236,7 @@ public class SearchParserTest extends SearchParser {
when(token.getLiteral()).thenReturn("word" + wordNumber);
wordNumber++;
} else if (aTokenArray == Token.PHRASE) {
- when(token.getLiteral()).thenReturn("phrase" + phraseNumber);
+ when(token.getLiteral()).thenReturn("\"phrase" + phraseNumber + "\"");
phraseNumber++;
}
when(token.toString()).thenReturn("" + aTokenArray);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/6235f3a4/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index ce4c3ca..8408e93 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -19,6 +19,7 @@
package org.apache.olingo.server.core.uri.parser.search;
import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
import java.util.ArrayList;
@@ -109,7 +110,40 @@ public class SearchTokenizerTest {
SearchValidator.init("abc or \"xyz\"").addExpected(WORD, WORD, PHRASE).validate();
}
+ /**
+ * https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-testcases.xml
+ * @throws Exception
+ */
@Test
+ @Ignore("Test must be moved to SearchParserTest and SearchParserAndTokenizerTest")
+ public void parsePhraseAbnfTestcases() throws Exception {
+ // <TestCase Name="5.1.7 Search - simple phrase" Rule="queryOptions">
+ SearchValidator.init("\"blue%20green\"").validate();
+ // <TestCase Name="5.1.7 Search - simple phrase" Rule="queryOptions">
+ SearchValidator.init("\"blue%20green%22").validate();
+ // <TestCase Name="5.1.7 Search - phrase with escaped double-quote" Rule="queryOptions">
+ // <Input>$search="blue\"green"</Input>
+ SearchValidator.init("\"blue\\\"green\"").validate();
+
+ // <TestCase Name="5.1.7 Search - phrase with escaped backslash" Rule="queryOptions">
+ // <Input>$search="blue\\green"</Input>
+ SearchValidator.init("\"blue\\\\green\"").validate();
+
+ // <TestCase Name="5.1.7 Search - phrase with unescaped double-quote" Rule="queryOptions" FailAt="14">
+ SearchValidator.init("\"blue\"green\"").validate();
+
+ // <TestCase Name="5.1.7 Search - phrase with unescaped double-quote" Rule="queryOptions" FailAt="16">
+ SearchValidator.init("\"blue%22green\"").validate();
+
+// <TestCase Name="5.1.7 Search - implicit AND" Rule="queryOptions">
+// <Input>$search=blue green</Input>
+// SearchValidator.init("\"blue%20green\"").validate();
+ // <TestCase Name="5.1.7 Search - implicit AND, encoced" Rule="queryOptions">
+// SearchValidator.init("blue%20green").validate();
+ }
+
+
+ @Test
public void parseNot() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
[17/23] olingo-odata4 git commit: [OLINGO-568] Minor code clean up
Posted by mi...@apache.org.
[OLINGO-568] Minor code clean up
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/7d4944d1
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/7d4944d1
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/7d4944d1
Branch: refs/heads/master
Commit: 7d4944d10e3da762ea5d089b911aafcd3f6d73c5
Parents: 8457c0f
Author: mibo <mi...@apache.org>
Authored: Fri Nov 13 17:51:24 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Fri Nov 13 17:51:24 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchParser.java | 26 +++++++++++---------
.../uri/parser/search/SearchParserTest.java | 16 ++++++++----
2 files changed, 25 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7d4944d1/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index 2cd03c6..804ca67 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -21,6 +21,7 @@ package org.apache.olingo.server.core.uri.parser.search;
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
import org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token;
import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
@@ -55,7 +56,7 @@ public class SearchParser {
}
private SearchExpression processSearchExpression(SearchExpression left) throws SearchParserException {
- if (token == null) {
+ if (isEof()) {
return left;
}
@@ -149,15 +150,10 @@ public class SearchParser {
return new SearchBinaryImpl(left, SearchBinaryOperatorKind.OR, se);
}
- private RuntimeException illegalState() {
- return new RuntimeException();
- }
-
private SearchExpression processNot() throws SearchParserException {
nextToken();
if (isToken(Token.WORD) || isToken(Token.PHRASE)) {
- SearchExpression searchExpression = processTerm();
- return new SearchUnaryImpl(searchExpression.asSearchTerm());
+ return new SearchUnaryImpl(processWordOrPhrase());
}
throw new SearchParserException("NOT must be followed by a term not a " + token.getToken(),
SearchParserException.MessageKeys.INVALID_NOT_OPERAND, token.getToken().toString());
@@ -175,21 +171,27 @@ public class SearchParser {
if (isToken(SearchQueryToken.Token.NOT)) {
return processNot();
}
- if (isToken(SearchQueryToken.Token.PHRASE)) {
+ return processWordOrPhrase();
+ }
+
+ private SearchTerm processWordOrPhrase() throws SearchParserException {
+ if (isToken(Token.PHRASE)) {
return processPhrase();
- } else if (isToken(SearchQueryToken.Token.WORD)) {
+ } else if (isToken(Token.WORD)) {
return processWord();
}
- throw illegalState();
+ throw new SearchParserException("Expected PHRASE||WORD found: " + token.getToken(),
+ SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN,
+ Token.PHRASE.name() + "" + Token.WORD.name(), token.getToken().toString());
}
- private SearchTermImpl processWord() {
+ private SearchTerm processWord() {
String literal = token.getLiteral();
nextToken();
return new SearchTermImpl(literal);
}
- private SearchTermImpl processPhrase() {
+ private SearchTerm processPhrase() {
String literal = token.getLiteral();
nextToken();
return new SearchTermImpl(literal);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7d4944d1/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 0902e8a..97e941c 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -177,6 +177,12 @@ public class SearchParserTest extends SearchParser {
runEx(SearchParserException.MessageKeys.INVALID_NOT_OPERAND, Token.NOT, Token.AND);
}
+
+ @Test
+ public void notNotWord() throws Exception {
+ runEx(SearchParserException.MessageKeys.INVALID_NOT_OPERAND, Token.NOT, Token.NOT, Token.WORD);
+ }
+
@Test
public void doubleAnd() throws Exception {
runEx(SearchParserException.MessageKeys.INVALID_OPERATOR_AFTER_AND, Token.WORD, Token.AND, Token.AND, Token.WORD);
@@ -223,17 +229,17 @@ public class SearchParserTest extends SearchParser {
ArrayList<SearchQueryToken> tokenList = new ArrayList<SearchQueryToken>();
int wordNumber = 1;
int phraseNumber = 1;
- for (int i = 0; i < tokenArray.length; i++) {
+ for (Token aTokenArray : tokenArray) {
SearchQueryToken token = mock(SearchQueryToken.class);
- when(token.getToken()).thenReturn(tokenArray[i]);
- if (tokenArray[i] == Token.WORD) {
+ when(token.getToken()).thenReturn(aTokenArray);
+ if (aTokenArray == Token.WORD) {
when(token.getLiteral()).thenReturn("word" + wordNumber);
wordNumber++;
- } else if (tokenArray[i] == Token.PHRASE) {
+ } else if (aTokenArray == Token.PHRASE) {
when(token.getLiteral()).thenReturn("phrase" + phraseNumber);
phraseNumber++;
}
- when(token.toString()).thenReturn("" + tokenArray[i]);
+ when(token.toString()).thenReturn("" + aTokenArray);
tokenList.add(token);
}
return tokenList;
[23/23] olingo-odata4 git commit: [OLINGO-568] Added exception
messages and some tests
Posted by mi...@apache.org.
[OLINGO-568] Added exception messages and some tests
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/ae1b2754
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/ae1b2754
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/ae1b2754
Branch: refs/heads/master
Commit: ae1b2754b765a2519e7d9c1fa30e1a5af5de3862
Parents: 1a59a58
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Nov 17 15:58:28 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Tue Nov 17 15:58:28 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchParser.java | 4 +++-
.../parser/search/SearchParserException.java | 6 ++++-
.../server-core-exceptions-i18n.properties | 9 ++++++++
.../search/SearchParserAndTokenizerTest.java | 24 +++++++++-----------
4 files changed, 28 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae1b2754/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index a9fe332..2723024 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -39,7 +39,9 @@ public class SearchParser {
try {
searchExpression = parse(tokenizer.tokenize(searchQuery));
} catch (SearchTokenizerException e) {
- return null;
+ String message = e.getMessage();
+ throw new SearchParserException("Tokenizer exception with message: " + message,
+ SearchParserException.MessageKeys.TOKENIZER_EXCEPTION, message);
}
final SearchOptionImpl searchOption = new SearchOptionImpl();
searchOption.setSearchExpression(searchExpression);
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae1b2754/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
index 78a12be..9e612a0 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
@@ -24,7 +24,11 @@ public class SearchParserException extends UriParserSyntaxException {
private static final long serialVersionUID = 5781553037561337795L;
- public static enum MessageKeys implements MessageKey {
+ public enum MessageKeys implements MessageKey {
+ /** parameter: message */
+ TOKENIZER_EXCEPTION,
+ /** parameter: tokenCharacter */
+ INVALID_TOKEN_CHARACTER_FOUND,
/** parameter: operatorkind */
INVALID_BINARY_OPERATOR_POSITION,
/** parameter: operatorkind */
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae1b2754/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
index 28c6dd7..bfb9440 100644
--- a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
+++ b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties
@@ -37,6 +37,15 @@ UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system
UriParserSyntaxException.SYNTAX=The URI is malformed.
UriParserSyntaxException.DUPLICATED_ALIAS=Duplicated alias. An alias '%1$s' was already specified!.
+SearchParserException.TOKENIZER_EXCEPTION=Exception during tokenizer creation with message '%1$s'.
+SearchParserException.INVALID_TOKEN_CHARACTER_FOUND=Invalid token character with value '%1$s' found.
+SearchParserException.INVALID_BINARY_OPERATOR_POSITION=Invalid binary operator position for kind '%1$s' found.
+SearchParserException.INVALID_NOT_OPERAND=Invalid not operand for kind '%1$s' found.
+SearchParserException.EXPECTED_DIFFERENT_TOKEN=Expected token '%1$s' but found '%2$s'.
+SearchParserException.NO_EXPRESSION_FOUND=No expression found.
+SearchParserException.INVALID_OPERATOR_AFTER_AND=Invalid operator after AND found of kind '%1$s'.
+
+
UriParserSemanticException.FUNCTION_NOT_FOUND=The function import '%1$s' has no function with parameters '%2$s'.
UriParserSemanticException.RESOURCE_PART_ONLY_FOR_TYPED_PARTS='%1$s' is only allowed for typed parts.
UriParserSemanticException.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE=The resource part '%1$s' must be preceded by a structural type.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ae1b2754/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index 23cac8e..fa419a9 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -23,17 +23,19 @@ import static org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOp
import java.lang.reflect.Field;
+import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
import org.junit.Assert;
-import org.junit.Ignore;
import org.junit.Test;
public class SearchParserAndTokenizerTest {
@Test
public void basicParsing() throws Exception {
+ SearchExpressionValidator.init("\"99\"")
+ .validate(with("99"));
SearchExpressionValidator.init("a")
.validate(with("a"));
SearchExpressionValidator.init("a AND b")
@@ -70,16 +72,10 @@ public class SearchParserAndTokenizerTest {
.validate("{{'a' OR 'b'} AND {NOT 'c'}}");
}
- @Ignore
@Test
- public void sebuilder() {
- System.out.println(with("c", or("a", and("b"))).toString());
- System.out.println(with("a", and("b", and("c"))).toString());
- System.out.println(with("a").toString());
- System.out.println(with(not("a")).toString());
- System.out.println(with("a", and("b")).toString());
- System.out.println(with("a", or("b")).toString());
- System.out.println(with("a", and(not("b"))).toString());
+ public void invalidSearchQuery() throws Exception {
+ SearchExpressionValidator.init("99").validate(SearchParserException.class,
+ SearchParserException.MessageKeys.TOKENIZER_EXCEPTION);
}
private static SearchExpression with(String term) {
@@ -162,11 +158,13 @@ public class SearchParserAndTokenizerTest {
return this;
}
- private void validate(Class<? extends Exception> exception) throws SearchTokenizerException {
+ private void validate(Class<? extends ODataLibraryException> exception, ODataLibraryException.MessageKey key)
+ throws SearchTokenizerException {
try {
- new SearchTokenizer().tokenize(searchQuery);
- } catch (Exception e) {
+ validate(searchQuery);
+ } catch (ODataLibraryException e) {
Assert.assertEquals(exception, e.getClass());
+ Assert.assertEquals(key, e.getMessageKey());
return;
}
Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
[04/23] olingo-odata4 git commit: [OLINGO-568] Added implicit AND
support
Posted by mi...@apache.org.
[OLINGO-568] Added implicit AND support
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/bbdd0d75
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/bbdd0d75
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/bbdd0d75
Branch: refs/heads/master
Commit: bbdd0d755ed43d61b61d5eba87aed6d2cab410c4
Parents: 762c924
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Nov 9 12:02:02 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Nov 9 12:02:02 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchTokenizer.java | 62 +++++++++++++++++---
.../uri/parser/search/SearchParserTest.java | 5 +-
.../uri/parser/search/SearchTokenizerTest.java | 39 +++++++++---
3 files changed, 89 insertions(+), 17 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bbdd0d75/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 951d641..e058a00 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -39,6 +39,7 @@ import java.util.List;
* </code>
*/
public class SearchTokenizer {
+ public static final char QUOTATION_MARK = '\"';
//RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
//BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
@@ -170,6 +171,8 @@ public class SearchTokenizer {
return new CloseState();
} else if(isEof(c)) {
return finish();
+ } else if(isWhitespace(c)) {
+ return new AndState(c);
} else {
return new SearchTermState().init(c);
}
@@ -189,7 +192,7 @@ public class SearchTokenizer {
public State nextChar(char c) {
if(c == 'n' || c == 'N') {
return new NotState(c);
- } else if (c == '\'') {
+ } else if (c == QUOTATION_MARK) {
return new SearchPhraseState(c);
} else if (isAllowedChar(c)) {
return new SearchWordState(c);
@@ -230,7 +233,7 @@ public class SearchTokenizer {
private class SearchPhraseState extends LiteralState {
public SearchPhraseState(char c) {
super(Token.PHRASE, c);
- if(c != '\'') {
+ if(c != QUOTATION_MARK) {
forbidden(c);
}
}
@@ -241,7 +244,7 @@ public class SearchTokenizer {
return new SearchExpressionState().init(c);
} else if (isAllowedPhrase(c)) {
return allowed(c);
- } else if (c == '\'') {
+ } else if (c == QUOTATION_MARK) {
finish();
return allowed(c);
} else if (isWhitespace(c)) {
@@ -299,13 +302,29 @@ public class SearchTokenizer {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
- return new RwsState();
+ return new BeforeSearchExpressionRwsState();
} else {
return new SearchWordState(this);
}
}
}
+ private class ImplicitAndState extends LiteralState {
+ private State followingState;
+ public ImplicitAndState(char c) {
+ super(Token.AND);
+ finish();
+ followingState = new SearchExpressionState().init(c);
+ }
+ public State nextState() {
+ return followingState;
+ }
+ @Override
+ public State nextChar(char c) {
+ return followingState.nextChar(c);
+ }
+ }
+
private class AndState extends LiteralState {
public AndState(char c) {
super(Token.AND, c);
@@ -321,7 +340,7 @@ public class SearchTokenizer {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
- return new RwsState();
+ return new BeforeSearchExpressionRwsState();
} else {
return new SearchWordState(this);
}
@@ -341,13 +360,28 @@ public class SearchTokenizer {
return allowed(c);
} else if(getLiteral().length() == 2 && isWhitespace(c)) {
finish();
- return new RwsState();
+ return new BeforeSearchExpressionRwsState();
} else {
return new SearchWordState(this);
}
}
}
+ // RWS [ 'AND' RWS ] searchExpr
+ private class BeforeSearchExpressionRwsState extends State {
+ public BeforeSearchExpressionRwsState() {
+ super(Token.RWS);
+ }
+ @Override
+ public State nextChar(char c) {
+ if (isWhitespace(c)) {
+ return allowed(c);
+ } else {
+ return new SearchExpressionState().init(c);
+ }
+ }
+ }
+
private class RwsState extends State {
public RwsState() {
@@ -362,7 +396,7 @@ public class SearchTokenizer {
} else if (c == 'A' || c == 'a') {
return new AndState(c);
} else {
- return new SearchExpressionState().init(c);
+ return new ImplicitAndState(c);
}
}
}
@@ -373,16 +407,26 @@ public class SearchTokenizer {
State state = new SearchExpressionState();
List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
+ State lastAddedToken = null;
for (char aChar : chars) {
State next = state.nextChar(aChar);
- if (state.isFinished() && next != state) {
+ if (next instanceof ImplicitAndState) {
+ lastAddedToken = next;
+ states.add(next);
+ next = ((ImplicitAndState)next).nextState();
+ } else if (state.isFinished() && state != lastAddedToken) {
+ lastAddedToken = state;
states.add(state);
}
state = next;
}
- if(state.nextChar(State.EOF).isFinished()) {
+ final State lastState = state.nextChar(State.EOF);
+ if(lastState.isFinished()) {
states.add(state);
+ if(state.getToken() != lastState.getToken()) {
+ states.add(lastState);
+ }
} else {
throw new IllegalStateException("State: " + state + " not finished and list is: " + states.toString());
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bbdd0d75/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 81147ba..0c51ba6 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -18,6 +18,8 @@
*/
package org.apache.olingo.server.core.uri.parser.search;
+import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
import org.junit.Test;
public class SearchParserTest {
@@ -25,6 +27,7 @@ public class SearchParserTest {
@Test
public void basicParsing() {
SearchParser parser = new SearchParser();
- parser.parse("ESAllPrim", "abc");
+ SearchOption so = parser.parse("ESAllPrim", "abc");
+ SearchExpression se = so.getSearchExpression();
}
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/bbdd0d75/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 24d782f..ceae8d8 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -87,24 +87,24 @@ public class SearchTokenizerTest {
List<SearchQueryToken> result;
//
- result = tokenizer.tokenize("'abc'");
+ result = tokenizer.tokenize("\"abc\"");
Assert.assertNotNull(result);
log(result.toString());
Assert.assertEquals(PHRASE, result.get(0).getToken());
//
- result = tokenizer.tokenize("'9988 abs'");
+ result = tokenizer.tokenize("\"9988 abs\"");
Assert.assertNotNull(result);
log(result.toString());
Assert.assertEquals(PHRASE, result.get(0).getToken());
- Assert.assertEquals("'9988 abs'", result.get(0).getLiteral());
+ Assert.assertEquals("\"9988 abs\"", result.get(0).getLiteral());
//
- result = tokenizer.tokenize("'99_88.'");
+ result = tokenizer.tokenize("\"99_88.\"");
Assert.assertNotNull(result);
log(result.toString());
Assert.assertEquals(PHRASE, result.get(0).getToken());
- Assert.assertEquals("'99_88.'", result.get(0).getLiteral());
+ Assert.assertEquals("\"99_88.\"", result.get(0).getLiteral());
}
@Test
@@ -142,6 +142,15 @@ public class SearchTokenizerTest {
}
@Test
+ public void parseImplicitAnd() {
+ SearchValidator.init("a b").addExpected(WORD, AND, WORD).validate();
+ SearchValidator.init("a b OR c").addExpected(WORD, AND, WORD, OR, WORD).validate();
+ SearchValidator.init("a bc OR c").addExpected(WORD, AND, WORD, OR, WORD).validate();
+ SearchValidator.init("a bc c").addExpected(WORD, AND, WORD, AND, WORD).validate();
+ SearchValidator.init("(a OR x) bc c").addExpected(OPEN, WORD, OR, WORD, CLOSE, AND, WORD, AND, WORD).validate();
+ }
+
+ @Test
public void testParseAnd() throws Exception {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
@@ -153,6 +162,22 @@ public class SearchTokenizerTest {
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(WORD, result.get(2).getToken());
+ // no lower case allowed for AND
+ result = tokenizer.tokenize("abc and xyz");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+
+ // implicit AND
+ result = tokenizer.tokenize("abc xyz");
+ Assert.assertNotNull(result);
+ log(result.toString());
+ Assert.assertEquals(WORD, result.get(0).getToken());
+ Assert.assertEquals(AND, result.get(1).getToken());
+ Assert.assertEquals(WORD, result.get(2).getToken());
+
result = tokenizer.tokenize("abc AND xyz AND 123");
Assert.assertNotNull(result);
log(result.toString());
@@ -162,13 +187,13 @@ public class SearchTokenizerTest {
Assert.assertEquals(AND, result.get(3).getToken());
Assert.assertEquals(WORD, result.get(4).getToken());
- result = tokenizer.tokenize("abc AND 'x-y_z' AND 123");
+ result = tokenizer.tokenize("abc AND \"x-y_z\" AND 123");
Assert.assertNotNull(result);
log(result.toString());
Assert.assertEquals(WORD, result.get(0).getToken());
Assert.assertEquals(AND, result.get(1).getToken());
Assert.assertEquals(PHRASE, result.get(2).getToken());
- Assert.assertEquals("'x-y_z'", result.get(2).getLiteral());
+ Assert.assertEquals("\"x-y_z\"", result.get(2).getLiteral());
Assert.assertEquals(AND, result.get(3).getToken());
Assert.assertEquals(WORD, result.get(4).getToken());
}
[13/23] olingo-odata4 git commit: [OLINGO-568] Fix unused stuff
Posted by mi...@apache.org.
[OLINGO-568] Fix unused stuff
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/a8d63fbe
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/a8d63fbe
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/a8d63fbe
Branch: refs/heads/master
Commit: a8d63fbee2c145c029fb5a2f8e927b9d7ac4e665
Parents: 22d152f
Author: Christian Amend <ch...@sap.com>
Authored: Thu Nov 12 14:05:55 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Thu Nov 12 14:05:55 2015 +0100
----------------------------------------------------------------------
.../server/core/uri/parser/search/SearchTokenizerException.java | 3 +++
.../core/uri/parser/search/SearchParserAndTokenizerTest.java | 1 +
.../olingo/server/core/uri/parser/search/SearchTokenizerTest.java | 2 ++
3 files changed, 6 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8d63fbe/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
index dd6f71e..451632b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
@@ -19,6 +19,9 @@
package org.apache.olingo.server.core.uri.parser.search;
public class SearchTokenizerException extends Exception {
+
+ private static final long serialVersionUID = -8295456415309640166L;
+
public SearchTokenizerException(String message) {
super(message);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8d63fbe/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index ca9d80b..43b63c3 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -139,6 +139,7 @@ public class SearchParserAndTokenizerTest {
return new SearchExpressionValidator(searchQuery);
}
+ @SuppressWarnings("unused")
private SearchExpressionValidator enableLogging() {
log = true;
return this;
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a8d63fbe/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 904bd3f..ce4c3ca 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -416,6 +416,8 @@ public class SearchTokenizerTest {
private static SearchValidator init(String searchQuery) {
return new SearchValidator(searchQuery);
}
+
+ @SuppressWarnings("unused")
private SearchValidator enableLogging() {
log = true;
return this;
[03/23] olingo-odata4 git commit: [OLINGO-568] Merge branch 'master'
into OLINGO-568_SearchParserPoC
Posted by mi...@apache.org.
[OLINGO-568] Merge branch 'master' into OLINGO-568_SearchParserPoC
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/762c924c
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/762c924c
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/762c924c
Branch: refs/heads/master
Commit: 762c924cf6a187f513bafe97d4702d4377bab655
Parents: 81fcbea 639362c
Author: mibo <mi...@apache.org>
Authored: Fri Nov 6 21:33:03 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Fri Nov 6 21:33:03 2015 +0100
----------------------------------------------------------------------
.../olingo/fit/tecsvc/client/BasicITCase.java | 8 +-
.../tecsvc/client/FilterSystemQueryITCase.java | 2 +-
.../deserializer/xml/ODataXmlDeserializer.java | 188 +-
.../serializer/json/ODataJsonSerializer.java | 7 +-
.../olingo/server/tecsvc/data/DataCreator.java | 1052 +--
.../olingo/server/tecsvc/data/DataProvider.java | 51 +-
.../tecsvc/provider/ComplexTypeProvider.java | 2 +-
.../tecsvc/provider/EntityTypeProvider.java | 8 +-
.../tecsvc/provider/PropertyProvider.java | 9 +-
.../json/ODataJsonDeserializerEntityTest.java | 25 +
.../xml/ODataXmlDeserializerTest.java | 4 +-
.../json/ODataJsonSerializerTest.java | 60 +-
.../serializer/xml/ODataXmlSerializerTest.java | 2 -
.../core/uri/antlr/TestFullResourcePath.java | 6130 +++++++++---------
...tityETMixEnumDefCollCompWithEnumStrings.json | 24 +
15 files changed, 3867 insertions(+), 3705 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/762c924c/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --cc lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index 259b61f,69458ab..ffc91e8
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@@ -1127,60 -1146,59 +1146,60 @@@ public class TestFullResourcePath
@Test
public void runNonComposableFunctions() throws Exception {
testUri.run("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')")
- .isKind(UriInfoKind.resource)
- .goPath().first()
- .isFunctionImport("FICRTCollETMixPrimCollCompTwoParam")
- .isFunction("UFCRTCollETMixPrimCollCompTwoParam")
- .isParameter(0, "ParameterInt16", "1")
- .isParameter(1, "ParameterString", "'1'");
-
+ .isKind(UriInfoKind.resource)
+ .goPath().first()
+ .isFunctionImport("FICRTCollETMixPrimCollCompTwoParam")
+ .isFunction("UFCRTCollETMixPrimCollCompTwoParam")
+ .isParameter(0, "ParameterInt16", "1")
+ .isParameter(1, "ParameterString", "'1'");
+
testUri.run("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')(0)")
- .isKind(UriInfoKind.resource)
- .goPath().first()
- .isFunctionImport("FICRTCollETMixPrimCollCompTwoParam")
- .isFunction("UFCRTCollETMixPrimCollCompTwoParam")
- .isParameter(0, "ParameterInt16", "1")
- .isParameter(1, "ParameterString", "'1'");
-
+ .isKind(UriInfoKind.resource)
+ .goPath().first()
+ .isFunctionImport("FICRTCollETMixPrimCollCompTwoParam")
+ .isFunction("UFCRTCollETMixPrimCollCompTwoParam")
+ .isParameter(0, "ParameterInt16", "1")
+ .isParameter(1, "ParameterString", "'1'");
+
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')(0)/PropertyInt16")
- .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
-
+ .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
+
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$skip=1")
- .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
-
+ .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$top=1")
- .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
-
- testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')",
+ .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
+ testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')",
"$filter=PropertyInt16 eq 1")
- .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
-
+ .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$skip=1")
- .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
-
+ .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$count=true")
- .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
-
+ .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$skiptoken=5")
- .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
-
+ .isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
+
// $search is currently not implemented. Please change this exception if the implementation is done.
- testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
- .isExSemantic(MessageKeys.NOT_IMPLEMENTED);
-
+ // FIXME (151106:mibo): check after finish of OLINGO-568
+// testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
+// .isExSemantic(MessageKeys.NOT_IMPLEMENTED);
+
testUri.run("ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()")
- .isKind(UriInfoKind.resource)
- .goPath().first()
- .isEntitySet("ESAllPrim")
- .at(1)
- .isFunction("BFNESAllPrimRTCTAllPrim");
-
- testUri.runEx("ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()"
- + "/PropertyString")
- .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
+ .isKind(UriInfoKind.resource)
+ .goPath().first()
+ .isEntitySet("ESAllPrim")
+ .at(1)
+ .isFunction("BFNESAllPrimRTCTAllPrim");
+
+ testUri.runEx("ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()"
+ + "/PropertyString")
+ .isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
}
-
+
@Test
public void runEsNameCast() throws Exception {
testUri.run("ESTwoPrim/olingo.odata.test1.ETBase")
[19/23] olingo-odata4 git commit: [OLINGO-568] Added search
integration test
Posted by mi...@apache.org.
[OLINGO-568] Added search integration test
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/9ff30e72
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/9ff30e72
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/9ff30e72
Branch: refs/heads/master
Commit: 9ff30e729dffe392dca1dba70356580266e2aef6
Parents: 21e115b
Author: mibo <mi...@apache.org>
Authored: Tue Nov 17 06:21:35 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Tue Nov 17 06:30:23 2015 +0100
----------------------------------------------------------------------
.../tecsvc/client/SystemQueryOptionITCase.java | 42 +++++++++++++++-----
.../queryoptions/options/SearchHandler.java | 3 +-
2 files changed, 35 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9ff30e72/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
index 4341a53..e605836 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java
@@ -21,10 +21,11 @@ package org.apache.olingo.fit.tecsvc.client;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import java.io.IOException;
import java.net.URI;
+import java.util.List;
import org.apache.olingo.client.api.communication.ODataClientErrorException;
-import org.apache.olingo.client.api.communication.ODataServerErrorException;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.domain.ClientEntity;
@@ -301,18 +302,41 @@ public class SystemQueryOptionITCase extends AbstractParamTecSvcITCase {
}
@Test
- public void negativeSearch() {
+ public void basicSearch() {
ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
.getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
.appendEntitySetSegment(ES_ALL_PRIM)
- .search("ABC")
+ .search("Second")
.build());
setCookieHeader(request);
- try {
- request.execute();
- fail();
- } catch (ODataServerErrorException e) {
- assertEquals("HTTP/1.1 501 Not Implemented", e.getMessage());
- }
+ ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+ List<ClientEntity> entities = response.getBody().getEntities();
+ assertEquals(1, entities.size());
+ }
+
+ @Test
+ public void andSearch() {
+ ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
+ .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
+ .appendEntitySetSegment(ES_ALL_PRIM)
+ .search("Second AND positive")
+ .build());
+ setCookieHeader(request);
+ ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+ List<ClientEntity> entities = response.getBody().getEntities();
+ assertEquals(0, entities.size());
+ }
+
+ @Test
+ public void orSearch() {
+ ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
+ .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
+ .appendEntitySetSegment(ES_ALL_PRIM)
+ .search("Second OR positive")
+ .build());
+ setCookieHeader(request);
+ ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+ List<ClientEntity> entities = response.getBody().getEntities();
+ assertEquals(2, entities.size());
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/9ff30e72/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
index 5ce4530..e56e083 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/SearchHandler.java
@@ -58,7 +58,8 @@ public class SearchHandler {
}
private static boolean isTrue(SearchTerm term, Property property) {
- if(property.isPrimitive()) {
+ if(property.isPrimitive() && !property.isNull()) {
+ // TODO: mibo(151117): pass EDM information to do correct 'string' convertation
String propertyString = property.asPrimitive().toString();
return propertyString != null && propertyString.contains(term.getSearchTerm());
}
[02/23] olingo-odata4 git commit: [OLINGO-568] Minor tokenizer
optimization
Posted by mi...@apache.org.
[OLINGO-568] Minor tokenizer optimization
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/81fcbeaf
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/81fcbeaf
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/81fcbeaf
Branch: refs/heads/master
Commit: 81fcbeafcf281ce07fa90b0ac58876c59e569ff1
Parents: 452ebcb
Author: mibo <mi...@apache.org>
Authored: Fri Nov 6 21:31:35 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Fri Nov 6 21:31:35 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchTokenizer.java | 120 +++++++++----------
.../uri/parser/search/SearchTokenizerTest.java | 2 +-
2 files changed, 59 insertions(+), 63 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/81fcbeaf/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 7d2b559..951d641 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -46,39 +46,16 @@ public class SearchTokenizer {
private static abstract class State implements SearchQueryToken {
private Token token = null;
private boolean finished = false;
- private final StringBuilder literal;
public static final char EOF = 0x03;
public State(Token t) {
token = t;
- literal = new StringBuilder();
- }
- public State(Token t, char c) {
- this(t);
- init(c);
- }
- public State(Token t, State consumeState) {
- token = t;
- literal = new StringBuilder(consumeState.getLiteral());
}
protected abstract State nextChar(char c);
- public State next(char c) {
- return nextChar(c);
- }
-
- public State init(char c) {
- if(isFinished()) {
- throw new IllegalStateException(toString() + " is already finished.");
- }
- literal.append(c);
- return this;
- }
-
public State allowed(char c) {
- literal.append(c);
return this;
}
@@ -139,27 +116,58 @@ public class SearchTokenizer {
@Override
public String getLiteral() {
- return literal.toString();
+ return token.toString();
}
@Override
public String toString() {
- return this.getToken().toString() + "=>{" + literal.toString() + "}";
+ return this.getToken().toString() + "=>{" + getLiteral() + "}";
+ }
+ }
+
+ private static abstract class LiteralState extends State {
+ private final StringBuilder literal = new StringBuilder();
+ public LiteralState(Token t) {
+ super(t);
+ }
+ public LiteralState(Token t, char c) {
+ super(t);
+ init(c);
+ }
+ public LiteralState(Token t, String initLiteral) {
+ super(t);
+ literal.append(initLiteral);
+ }
+ public State allowed(char c) {
+ literal.append(c);
+ return this;
+ }
+ @Override
+ public String getLiteral() {
+ return literal.toString();
+ }
+
+ public State init(char c) {
+ if(isFinished()) {
+ throw new IllegalStateException(toString() + " is already finished.");
+ }
+ literal.append(c);
+ return this;
}
}
- private class SearchExpressionState extends State {
+ private class SearchExpressionState extends LiteralState {
public SearchExpressionState() {
super(Token.SEARCH_EXPRESSION);
}
@Override
public State nextChar(char c) {
if (c == '(') {
- return new OpenState(c);
+ return new OpenState();
} else if (isWhitespace(c)) {
- return new RwsState(c);
+ return new RwsState();
} else if(c == ')') {
- return new CloseState(c);
+ return new CloseState();
} else if(isEof(c)) {
return finish();
} else {
@@ -173,7 +181,7 @@ public class SearchTokenizer {
}
}
- private class SearchTermState extends State {
+ private class SearchTermState extends LiteralState {
public SearchTermState() {
super(Token.TERM);
}
@@ -185,14 +193,6 @@ public class SearchTokenizer {
return new SearchPhraseState(c);
} else if (isAllowedChar(c)) {
return new SearchWordState(c);
- } else if (c == ')') {
- finish();
- return new CloseState(c);
- } else if (isWhitespace(c)) {
- finish();
- return new RwsState(c);
- } else if (isEof(c)) {
- return finish();
}
throw new IllegalStateException(this.getClass().getName() + "->" + c);
}
@@ -202,27 +202,24 @@ public class SearchTokenizer {
}
}
- private class SearchWordState extends State {
+ private class SearchWordState extends LiteralState {
public SearchWordState(char c) {
super(Token.WORD, c);
}
public SearchWordState(State toConsume) {
- super(Token.WORD, toConsume);
+ super(Token.WORD, toConsume.getLiteral());
}
@Override
public State nextChar(char c) {
- // if(c == 'n' || c == 'N') {
- // return new NotState(c);
- // }
if (isAllowedChar(c)) {
return allowed(c);
} else if (c == ')') {
finish();
- return new CloseState(c);
+ return new CloseState();
} else if (isWhitespace(c)) {
finish();
- return new RwsState(c);
+ return new RwsState();
} else if (isEof(c)) {
return finish();
}
@@ -230,7 +227,7 @@ public class SearchTokenizer {
}
}
- private class SearchPhraseState extends State {
+ private class SearchPhraseState extends LiteralState {
public SearchPhraseState(char c) {
super(Token.PHRASE, c);
if(c != '\'') {
@@ -249,7 +246,7 @@ public class SearchTokenizer {
return allowed(c);
} else if (isWhitespace(c)) {
if(isFinished()) {
- return new RwsState(c);
+ return new RwsState();
}
return allowed(c);
} else if (isEof(c)) {
@@ -260,8 +257,8 @@ public class SearchTokenizer {
}
private class OpenState extends State {
- public OpenState(char c) {
- super(Token.OPEN, c);
+ public OpenState() {
+ super(Token.OPEN);
finish();
}
@Override
@@ -275,8 +272,8 @@ public class SearchTokenizer {
}
private class CloseState extends State {
- public CloseState(char c) {
- super(Token.CLOSE, c);
+ public CloseState() {
+ super(Token.CLOSE);
finish();
}
@@ -290,7 +287,7 @@ public class SearchTokenizer {
}
}
- private class NotState extends State {
+ private class NotState extends LiteralState {
public NotState(char c) {
super(Token.NOT, c);
}
@@ -302,14 +299,14 @@ public class SearchTokenizer {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
- return new RwsState(c);
+ return new RwsState();
} else {
return new SearchWordState(this);
}
}
}
- private class AndState extends State {
+ private class AndState extends LiteralState {
public AndState(char c) {
super(Token.AND, c);
if(c != 'a' && c != 'A') {
@@ -324,14 +321,14 @@ public class SearchTokenizer {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
- return new RwsState(c);
+ return new RwsState();
} else {
return new SearchWordState(this);
}
}
}
- private class OrState extends State {
+ private class OrState extends LiteralState {
public OrState(char c) {
super(Token.OR, c);
if(c != 'o' && c != 'O') {
@@ -344,7 +341,7 @@ public class SearchTokenizer {
return allowed(c);
} else if(getLiteral().length() == 2 && isWhitespace(c)) {
finish();
- return new RwsState(c);
+ return new RwsState();
} else {
return new SearchWordState(this);
}
@@ -353,8 +350,8 @@ public class SearchTokenizer {
private class RwsState extends State {
- public RwsState(char c) {
- super(Token.RWS, c);
+ public RwsState() {
+ super(Token.RWS);
}
@Override
public State nextChar(char c) {
@@ -377,14 +374,14 @@ public class SearchTokenizer {
State state = new SearchExpressionState();
List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
for (char aChar : chars) {
- State next = state.next(aChar);
+ State next = state.nextChar(aChar);
if (state.isFinished() && next != state) {
states.add(state);
}
state = next;
}
- if(state.next(State.EOF).isFinished()) {
+ if(state.nextChar(State.EOF).isFinished()) {
states.add(state);
} else {
throw new IllegalStateException("State: " + state + " not finished and list is: " + states.toString());
@@ -392,5 +389,4 @@ public class SearchTokenizer {
return states;
}
-
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/81fcbeaf/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 15d35df..24d782f 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -220,7 +220,7 @@ public class SearchTokenizerTest {
.validate();
- SearchValidator.init("(foo OR that) AND (bar OR baz)").enableLogging()
+ SearchValidator.init("(foo OR that) AND (bar OR baz)")
.addExpected(OPEN)
.addExpected(WORD, "foo").addExpected(OR).addExpected(WORD, "that")
.addExpected(CLOSE).addExpected(AND).addExpected(OPEN)
[09/23] olingo-odata4 git commit: [OLINGO-568] Added
SearchTokenizerException
Posted by mi...@apache.org.
[OLINGO-568] Added SearchTokenizerException
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/3eef0bf6
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/3eef0bf6
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/3eef0bf6
Branch: refs/heads/master
Commit: 3eef0bf605b4eff6c724f15e661d9c9c44964ddc
Parents: f64abe1
Author: mibo <mi...@apache.org>
Authored: Tue Nov 10 20:10:02 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Tue Nov 10 20:10:02 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchParser.java | 6 +-
.../core/uri/parser/search/SearchTokenizer.java | 63 ++++++++++----------
.../parser/search/SearchTokenizerException.java | 25 ++++++++
.../uri/parser/search/SearchTokenizerTest.java | 31 ++++++----
4 files changed, 82 insertions(+), 43 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3eef0bf6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index d508932..ca45037 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -27,7 +27,11 @@ public class SearchParser {
public SearchOption parse(String path, String value) {
SearchTokenizer tokenizer = new SearchTokenizer();
- List<SearchQueryToken> tokens = tokenizer.tokenize(value);
+ try {
+ List<SearchQueryToken> tokens = tokenizer.tokenize(value);
+ } catch (SearchTokenizerException e) {
+ return null;
+ }
return new SearchOptionImpl();
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3eef0bf6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index f393d22..1ec4df1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -58,14 +58,14 @@ public class SearchTokenizer {
token = t;
}
- protected abstract State nextChar(char c);
+ protected abstract State nextChar(char c) throws SearchTokenizerException;
public State allowed(char c) {
return this;
}
- public State forbidden(char c) {
- throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ public State forbidden(char c) throws SearchTokenizerException {
+ throw new SearchTokenizerException("Forbidden character for " + this.getClass().getName() + "->" + c);
}
public State finish() {
@@ -105,7 +105,7 @@ public class SearchTokenizer {
* @return true if character is allowed for a phrase
*/
static boolean isAllowedPhrase(final char character) {
- // FIXME mibo: check missing and '\''
+ // FIXME mibo: check missing
return isAllowedChar(character)
|| character == '-'
|| character == '.'
@@ -115,6 +115,7 @@ public class SearchTokenizer {
|| character == '@'
|| character == '/'
|| character == '$'
+ || character == '\''
|| character == '=';
}
@@ -142,7 +143,7 @@ public class SearchTokenizer {
public LiteralState(Token t) {
super(t);
}
- public LiteralState(Token t, char c) {
+ public LiteralState(Token t, char c) throws SearchTokenizerException {
super(t);
init(c);
}
@@ -159,9 +160,9 @@ public class SearchTokenizer {
return literal.toString();
}
- public State init(char c) {
+ public State init(char c) throws SearchTokenizerException {
if(isFinished()) {
- throw new IllegalStateException(toString() + " is already finished.");
+ throw new SearchTokenizerException(toString() + " is already finished.");
}
literal.append(c);
return this;
@@ -176,7 +177,7 @@ public class SearchTokenizer {
super(null, initLiteral);
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
if (c == CHAR_OPEN) {
return new OpenState();
} else if (isWhitespace(c)) {
@@ -189,7 +190,7 @@ public class SearchTokenizer {
}
@Override
- public State init(char c) {
+ public State init(char c) throws SearchTokenizerException {
return nextChar(c);
}
}
@@ -199,7 +200,7 @@ public class SearchTokenizer {
super(Token.TERM);
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
if(c == CHAR_N) {
return new NotState(c);
} else if (c == QUOTATION_MARK) {
@@ -207,16 +208,16 @@ public class SearchTokenizer {
} else if (isAllowedChar(c)) {
return new SearchWordState(c);
}
- throw new IllegalStateException(this.getClass().getName() + "->" + c);
+ return forbidden(c);
}
@Override
- public State init(char c) {
+ public State init(char c) throws SearchTokenizerException {
return nextChar(c);
}
}
private class SearchWordState extends LiteralState {
- public SearchWordState(char c) {
+ public SearchWordState(char c) throws SearchTokenizerException {
super(Token.WORD, c);
}
public SearchWordState(State toConsume) {
@@ -224,7 +225,7 @@ public class SearchTokenizer {
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
if (isAllowedChar(c)) {
return allowed(c);
} else if (c == CHAR_CLOSE) {
@@ -244,7 +245,7 @@ public class SearchTokenizer {
}
private class SearchPhraseState extends LiteralState {
- public SearchPhraseState(char c) {
+ public SearchPhraseState(char c) throws SearchTokenizerException {
super(Token.PHRASE, c);
if(c != QUOTATION_MARK) {
forbidden(c);
@@ -252,19 +253,17 @@ public class SearchTokenizer {
}
@Override
- public State nextChar(char c) {
- if(isFinished()) {
- return new SearchExpressionState().init(c);
- } else if (isAllowedPhrase(c)) {
+ public State nextChar(char c) throws SearchTokenizerException {
+ if (isAllowedPhrase(c)) {
+ return allowed(c);
+ } else if (isWhitespace(c)) {
return allowed(c);
} else if (c == QUOTATION_MARK) {
finish();
allowed(c);
return new SearchExpressionState();
- } else if (isWhitespace(c)) {
- return allowed(c);
- } else if (c == CHAR_CLOSE) {
- return allowed(c);
+ } else if(isFinished()) {
+ return new SearchExpressionState().init(c);
}
return forbidden(c);
}
@@ -276,7 +275,7 @@ public class SearchTokenizer {
finish();
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
finish();
if (isWhitespace(c)) {
return forbidden(c);
@@ -292,13 +291,13 @@ public class SearchTokenizer {
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
return new SearchExpressionState().init(c);
}
}
private class NotState extends LiteralState {
- public NotState(char c) {
+ public NotState(char c) throws SearchTokenizerException {
super(Token.NOT, c);
if(c != CHAR_N) {
forbidden(c);
@@ -306,11 +305,11 @@ public class SearchTokenizer {
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && c == CHAR_O) {
+ if (literal.length() == 1 && c == CHAR_O) {
return allowed(c);
- } else if (getLiteral().length() == 2 && c == CHAR_T) {
+ } else if (literal.length() == 2 && c == CHAR_T) {
return allowed(c);
- } else if(getLiteral().length() == 3 && isWhitespace(c)) {
+ } else if(literal.length() == 3 && isWhitespace(c)) {
finish();
return new BeforeSearchExpressionRwsState();
} else {
@@ -326,7 +325,7 @@ public class SearchTokenizer {
super(null);
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
if (isWhitespace(c)) {
return allowed(c);
} else {
@@ -342,7 +341,7 @@ public class SearchTokenizer {
super(null);
}
@Override
- public State nextChar(char c) {
+ public State nextChar(char c) throws SearchTokenizerException {
if (!noneRws && isWhitespace(c)) {
return allowed(c);
} else if (c == CHAR_O) {
@@ -374,7 +373,7 @@ public class SearchTokenizer {
}
// TODO (mibo): add (new) parse exception
- public List<SearchQueryToken> tokenize(String searchQuery) {
+ public List<SearchQueryToken> tokenize(String searchQuery) throws SearchTokenizerException {
char[] chars = searchQuery.toCharArray();
State state = new SearchExpressionState();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3eef0bf6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
new file mode 100644
index 0000000..dd6f71e
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
@@ -0,0 +1,25 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+public class SearchTokenizerException extends Exception {
+ public SearchTokenizerException(String message) {
+ super(message);
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3eef0bf6/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 548d3fd..ea3cab9 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -150,7 +150,7 @@ public class SearchTokenizerTest {
}
@Test
- public void parseImplicitAnd() {
+ public void parseImplicitAnd() throws SearchTokenizerException {
SearchValidator.init("a b").addExpected(WORD, AND, WORD).validate();
SearchValidator.init("a b OR c").addExpected(WORD, AND, WORD, OR, WORD).validate();
SearchValidator.init("a bc OR c").addExpected(WORD, AND, WORD, OR, WORD).validate();
@@ -305,7 +305,7 @@ public class SearchTokenizerTest {
}
@Test
- public void moreMixedTests() {
+ public void moreMixedTests() throws SearchTokenizerException {
validate("abc");
validate("NOT abc");
@@ -340,20 +340,23 @@ public class SearchTokenizerTest {
}
@Test
- public void parseInvalid() {
+ public void parseInvalid() throws SearchTokenizerException {
SearchValidator.init("abc AND OR something").validate();
+ SearchValidator.init("abc AND \"something\" )").validate();
+ //
+ SearchValidator.init("( abc AND) OR something").validate(SearchTokenizerException.class);
}
- public boolean validate(String query) {
- return new SearchValidator(query).validate();
+ public void validate(String query) throws SearchTokenizerException {
+ new SearchValidator(query).validate();
}
- public boolean validate(String query, SearchQueryToken.Token ... tokens) {
+ public void validate(String query, SearchQueryToken.Token ... tokens) throws SearchTokenizerException {
SearchValidator sv = new SearchValidator(query);
for (SearchQueryToken.Token token : tokens) {
sv.addExpected(token);
}
- return sv.validate();
+ sv.validate();
}
private static class SearchValidator {
@@ -393,7 +396,17 @@ public class SearchTokenizerTest {
}
return this;
}
- private boolean validate() {
+ private void validate(Class<? extends Exception> exception) throws SearchTokenizerException {
+ try {
+ new SearchTokenizer().tokenize(searchQuery);
+ } catch (Exception e) {
+ Assert.assertEquals(exception, e.getClass());
+ return;
+ }
+ Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
+ }
+
+ private void validate() throws SearchTokenizerException {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result = tokenizer.tokenize(searchQuery);
Assert.assertNotNull(result);
@@ -412,8 +425,6 @@ public class SearchTokenizerTest {
}
}
}
-
- return true;
}
}
[06/23] olingo-odata4 git commit: [OLINGO-568] Improved states
Posted by mi...@apache.org.
[OLINGO-568] Improved states
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/43bc49f9
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/43bc49f9
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/43bc49f9
Branch: refs/heads/master
Commit: 43bc49f9631189d1ac49ee5c7ff0875da83b3d73
Parents: b3bbfa6
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Nov 9 15:39:02 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Nov 9 15:39:02 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchTokenizer.java | 68 +++++++++-----------
.../uri/parser/search/SearchTokenizerTest.java | 13 +++-
2 files changed, 40 insertions(+), 41 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/43bc49f9/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index 67d4655..f62e0f4 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -82,6 +82,10 @@ public class SearchTokenizer {
return token;
}
+ public boolean close() {
+ return nextChar(EOF).isFinished();
+ }
+
static boolean isAllowedChar(final char character) {
// TODO mibo: add missing allowed characters
return CHAR_A <= character && character <= 'Z' // case A..Z
@@ -173,11 +177,9 @@ public class SearchTokenizer {
if (c == CHAR_OPEN) {
return new OpenState();
} else if (isWhitespace(c)) {
- return new RwsState();
+ return new RwsImplicitAndState();
} else if(c == CHAR_CLOSE) {
return new CloseState();
- } else if(isEof(c)) {
- return finish();
} else if(isWhitespace(c)) {
return new AndState(c);
} else {
@@ -186,6 +188,11 @@ public class SearchTokenizer {
}
@Override
+ public boolean close() {
+ return true;
+ }
+
+ @Override
public State init(char c) {
return nextChar(c);
}
@@ -229,7 +236,7 @@ public class SearchTokenizer {
return new CloseState();
} else if (isWhitespace(c)) {
finish();
- return new RwsState();
+ return new RwsImplicitAndState();
} else if (isEof(c)) {
return finish();
}
@@ -253,10 +260,16 @@ public class SearchTokenizer {
return allowed(c);
} else if (c == QUOTATION_MARK) {
finish();
- return allowed(c);
+ allowed(c);
+ return new SearchExpressionState();
} else if (isWhitespace(c)) {
if(isFinished()) {
- return new RwsState();
+ return new RwsImplicitAndState();
+ }
+ return allowed(c);
+ } else if (c == CHAR_CLOSE) {
+ if(isFinished()) {
+ return new CloseState();
}
return allowed(c);
} else if (isEof(c)) {
@@ -319,22 +332,6 @@ public class SearchTokenizer {
}
}
- private class ImplicitAndState extends LiteralState {
- private State followingState;
- public ImplicitAndState(char c) {
- super(Token.AND);
- finish();
- followingState = new SearchExpressionState().init(c);
- }
- public State nextState() {
- return followingState;
- }
- @Override
- public State nextChar(char c) {
- return followingState.nextChar(c);
- }
- }
-
private class AndState extends LiteralState {
public AndState(char c) {
super(Token.AND, c);
@@ -393,9 +390,10 @@ public class SearchTokenizer {
}
}
- private class RwsState extends State {
- public RwsState() {
- super(Token.RWS);
+ // implicit and
+ private class RwsImplicitAndState extends State {
+ public RwsImplicitAndState() {
+ super(Token.AND);
}
@Override
public State nextChar(char c) {
@@ -406,7 +404,8 @@ public class SearchTokenizer {
} else if (c == CHAR_A) {
return new AndState(c);
} else {
- return new ImplicitAndState(c);
+ finish();
+ return new SearchExpressionState().init(c);
}
}
}
@@ -417,25 +416,18 @@ public class SearchTokenizer {
State state = new SearchExpressionState();
List<SearchQueryToken> states = new ArrayList<SearchQueryToken>();
- State lastAdded = null;
for (char aChar : chars) {
State next = state.nextChar(aChar);
- if (next instanceof ImplicitAndState) {
- lastAdded = next;
- states.add(next);
- next = ((ImplicitAndState)next).nextState();
- } else if (state.isFinished() && state != lastAdded) {
- lastAdded = state;
+ if (state.isFinished()) {
states.add(state);
}
state = next;
}
- final State lastState = state.nextChar(State.EOF);
- if(lastState.isFinished()) {
- if(state != lastAdded) {
- states.add(state);
- }
+ if(state.close()) {
+ if(state.isFinished()) {
+ states.add(state);
+ }
} else {
throw new IllegalStateException("State: " + state + " not finished and list is: " + states.toString());
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/43bc49f9/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index 9044282..e53b6b2 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -86,6 +86,8 @@ public class SearchTokenizerTest {
SearchTokenizer tokenizer = new SearchTokenizer();
List<SearchQueryToken> result;
+ SearchValidator.init("abc AND \"x-y_z\" AND 123").validate();
+
//
result = tokenizer.tokenize("\"abc\"");
Assert.assertNotNull(result);
@@ -325,12 +327,17 @@ public class SearchTokenizerTest {
// parenthesis
validate("(abc)");
validate("(abc AND def)");
- validate("(abc AND def) OR ghi ");
- validate("(abc AND def) ghi ");
+ validate("(abc AND def) OR ghi");
+ validate("(abc AND def) ghi");
validate("abc AND (def OR ghi)");
validate("abc AND (def ghi)");
}
-
+
+ @Test
+ public void parseInvalid() {
+ SearchValidator.init("abc AND OR something").validate();
+ }
+
public boolean validate(String query) {
return new SearchValidator(query).validate();
}
[16/23] olingo-odata4 git commit: [OLINGO-568] SearchParser negative
tests
Posted by mi...@apache.org.
[OLINGO-568] SearchParser negative tests
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/8457c0f6
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/8457c0f6
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/8457c0f6
Branch: refs/heads/master
Commit: 8457c0f60a084f92f7a98c61039c9a5540980a3c
Parents: cef72e4
Author: Christian Amend <ch...@sap.com>
Authored: Fri Nov 13 14:56:29 2015 +0100
Committer: Christian Amend <ch...@sap.com>
Committed: Fri Nov 13 14:56:29 2015 +0100
----------------------------------------------------------------------
.../core/uri/parser/search/SearchParser.java | 89 ++++++++------
.../parser/search/SearchParserException.java | 54 +++++++++
.../core/uri/parser/search/SearchTokenizer.java | 110 ++++++++++-------
.../parser/search/SearchTokenizerException.java | 25 +++-
.../search/SearchParserAndTokenizerTest.java | 10 +-
.../uri/parser/search/SearchParserTest.java | 118 ++++++++++++++-----
6 files changed, 290 insertions(+), 116 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8457c0f6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index d5109a5..2cd03c6 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -6,9 +6,9 @@
* 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
- *
+ *
* 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
@@ -21,6 +21,7 @@ package org.apache.olingo.server.core.uri.parser.search;
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token;
import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
import java.util.Iterator;
@@ -31,13 +32,11 @@ public class SearchParser {
private Iterator<SearchQueryToken> tokens;
private SearchQueryToken token;
- public SearchOption parse(String path, String value) {
+ public SearchOption parse(String path, String value) throws SearchParserException, SearchTokenizerException {
SearchTokenizer tokenizer = new SearchTokenizer();
SearchExpression searchExpression;
try {
- tokens = tokenizer.tokenize(value).iterator();
- nextToken();
- searchExpression = processSearchExpression(null);
+ searchExpression = parseInternal(tokenizer.tokenize(value));
} catch (SearchTokenizerException e) {
return null;
}
@@ -46,32 +45,45 @@ public class SearchParser {
return searchOption;
}
- protected SearchExpression parseInternal(List<SearchQueryToken> tokens) {
+ protected SearchExpression parseInternal(List<SearchQueryToken> tokens) throws SearchParserException {
this.tokens = tokens.iterator();
nextToken();
+ if (token == null) {
+ throw new SearchParserException("No search String", SearchParserException.MessageKeys.NO_EXPRESSION_FOUND);
+ }
return processSearchExpression(null);
}
- private SearchExpression processSearchExpression(SearchExpression left) {
- if(token == null) {
+ private SearchExpression processSearchExpression(SearchExpression left) throws SearchParserException {
+ if (token == null) {
return left;
}
+ if (left == null && (isToken(SearchQueryToken.Token.AND) || isToken(SearchQueryToken.Token.OR))) {
+ throw new SearchParserException(token.getToken() + " needs a left operand.",
+ SearchParserException.MessageKeys.INVALID_BINARY_OPERATOR_POSITION, token.getToken().toString());
+ }
+
SearchExpression expression = left;
- if(isToken(SearchQueryToken.Token.OPEN)) {
+ if (isToken(SearchQueryToken.Token.OPEN)) {
processOpen();
expression = processSearchExpression(left);
validateToken(SearchQueryToken.Token.CLOSE);
processClose();
- } else if(isTerm()) {
+ } else if (isTerm()) {
expression = processTerm();
}
- if(isToken(SearchQueryToken.Token.AND) || isTerm()) {
- expression = processAnd(expression);
- } else if(isToken(SearchQueryToken.Token.OR)) {
- expression = processOr(expression);
- } else if(isEof()) {
+ if (expression == null) {
+ throw new SearchParserException("Brackets must contain an expression.",
+ SearchParserException.MessageKeys.NO_EXPRESSION_FOUND);
+ }
+
+ if (isToken(SearchQueryToken.Token.AND) || isToken(SearchQueryToken.Token.OPEN) || isTerm()) {
+ expression = processAnd(expression);
+ } else if (isToken(SearchQueryToken.Token.OR)) {
+ expression = processOr(expression);
+ } else if (isEof()) {
return expression;
}
return expression;
@@ -88,15 +100,17 @@ public class SearchParser {
}
private boolean isToken(SearchQueryToken.Token toCheckToken) {
- if(token == null) {
+ if (token == null) {
return false;
}
return token.getToken() == toCheckToken;
}
- private void validateToken(SearchQueryToken.Token toValidateToken) {
- if(!isToken(toValidateToken)) {
- throw illegalState();
+ private void validateToken(SearchQueryToken.Token toValidateToken) throws SearchParserException {
+ if (!isToken(toValidateToken)) {
+ String actualToken = token == null ? "null" : token.getToken().toString();
+ throw new SearchParserException("Expected " + toValidateToken + " but was " + actualToken,
+ SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN, toValidateToken.toString(), actualToken);
}
}
@@ -108,23 +122,27 @@ public class SearchParser {
nextToken();
}
- private SearchExpression processAnd(SearchExpression left) {
- if(isToken(SearchQueryToken.Token.AND)) {
+ private SearchExpression processAnd(SearchExpression left) throws SearchParserException {
+ if (isToken(SearchQueryToken.Token.AND)) {
nextToken();
}
SearchExpression se = left;
- if(isTerm()) {
+ if (isTerm()) {
se = processTerm();
se = new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, se);
return processSearchExpression(se);
} else {
+ if (isToken(SearchQueryToken.Token.AND) || isToken(SearchQueryToken.Token.OR)) {
+ throw new SearchParserException("Operators must not be followed by an AND or an OR",
+ SearchParserException.MessageKeys.INVALID_OPERATOR_AFTER_AND, token.getToken().toString());
+ }
se = processSearchExpression(se);
return new SearchBinaryImpl(left, SearchBinaryOperatorKind.AND, se);
}
}
- public SearchExpression processOr(SearchExpression left) {
- if(isToken(SearchQueryToken.Token.OR)) {
+ public SearchExpression processOr(SearchExpression left) throws SearchParserException {
+ if (isToken(SearchQueryToken.Token.OR)) {
nextToken();
}
SearchExpression se = processSearchExpression(left);
@@ -135,30 +153,31 @@ public class SearchParser {
return new RuntimeException();
}
- private SearchExpression processNot() {
+ private SearchExpression processNot() throws SearchParserException {
nextToken();
- SearchExpression searchExpression = processTerm();
- if(searchExpression.isSearchTerm()) {
+ if (isToken(Token.WORD) || isToken(Token.PHRASE)) {
+ SearchExpression searchExpression = processTerm();
return new SearchUnaryImpl(searchExpression.asSearchTerm());
}
- throw illegalState();
+ throw new SearchParserException("NOT must be followed by a term not a " + token.getToken(),
+ SearchParserException.MessageKeys.INVALID_NOT_OPERAND, token.getToken().toString());
}
private void nextToken() {
- if(tokens.hasNext()) {
- token = tokens.next();
+ if (tokens.hasNext()) {
+ token = tokens.next();
} else {
token = null;
}
}
- private SearchExpression processTerm() {
- if(isToken(SearchQueryToken.Token.NOT)) {
+ private SearchExpression processTerm() throws SearchParserException {
+ if (isToken(SearchQueryToken.Token.NOT)) {
return processNot();
}
- if(isToken(SearchQueryToken.Token.PHRASE)) {
+ if (isToken(SearchQueryToken.Token.PHRASE)) {
return processPhrase();
- } else if(isToken(SearchQueryToken.Token.WORD)) {
+ } else if (isToken(SearchQueryToken.Token.WORD)) {
return processWord();
}
throw illegalState();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8457c0f6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
new file mode 100644
index 0000000..78a12be
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParserException.java
@@ -0,0 +1,54 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+
+public class SearchParserException extends UriParserSyntaxException {
+
+ private static final long serialVersionUID = 5781553037561337795L;
+
+ public static enum MessageKeys implements MessageKey {
+ /** parameter: operatorkind */
+ INVALID_BINARY_OPERATOR_POSITION,
+ /** parameter: operatorkind */
+ INVALID_NOT_OPERAND,
+ /** parameters: expectedToken actualToken */
+ EXPECTED_DIFFERENT_TOKEN,
+ NO_EXPRESSION_FOUND,
+ /** parameter: operatorkind */
+ INVALID_OPERATOR_AFTER_AND;
+
+ @Override
+ public String getKey() {
+ return name();
+ }
+ }
+
+ public SearchParserException(final String developmentMessage, final MessageKey messageKey,
+ final String... parameters) {
+ super(developmentMessage, messageKey, parameters);
+ }
+
+ public SearchParserException(final String developmentMessage, final Throwable cause, final MessageKey messageKey,
+ final String... parameters) {
+ super(developmentMessage, cause, messageKey, parameters);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8457c0f6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index a9a5895..1e3b2ef 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -6,9 +6,9 @@
* 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
- *
+ *
* 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
@@ -24,18 +24,18 @@ import java.util.List;
/**
* <code>
* searchExpr = ( OPEN BWS searchExpr BWS CLOSE
- * / searchTerm
- * ) [ searchOrExpr
- * / searchAndExpr
- * ]
+ * / searchTerm
+ * ) [ searchOrExpr
+ * / searchAndExpr
+ * ]
*
- * searchOrExpr = RWS 'OR' RWS searchExpr
- * searchAndExpr = RWS [ 'AND' RWS ] searchExpr
+ * searchOrExpr = RWS 'OR' RWS searchExpr
+ * searchAndExpr = RWS [ 'AND' RWS ] searchExpr
*
- * searchTerm = [ 'NOT' RWS ] ( searchPhrase / searchWord )
- * searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
- * searchWord = 1*ALPHA ; Actually: any character from the Unicode categories L or Nl,
- * ; but not the words AND, OR, and NOT
+ * searchTerm = [ 'NOT' RWS ] ( searchPhrase / searchWord )
+ * searchPhrase = quotation-mark 1*qchar-no-AMP-DQUOTE quotation-mark
+ * searchWord = 1*ALPHA ; Actually: any character from the Unicode categories L or Nl,
+ * ; but not the words AND, OR, and NOT
* </code>
*/
public class SearchTokenizer {
@@ -65,7 +65,8 @@ public class SearchTokenizer {
}
public State forbidden(char c) throws SearchTokenizerException {
- throw new SearchTokenizerException("Forbidden character for " + this.getClass().getName() + "->" + c);
+ throw new SearchTokenizerException("Forbidden character for " + this.getClass().getName() + "->" + c,
+ SearchTokenizerException.MessageKeys.FORBIDDEN_CHARACTER, "" + c);
}
public State finish() {
@@ -97,20 +98,20 @@ public class SearchTokenizer {
}
/**
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
- * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ * other-delims = "!" / "(" / ")" / "*" / "+" / "," / ";"
* qchar-unescaped = unreserved / pct-encoded-unescaped / other-delims / ":" / "@" / "/" / "?" / "$" / "'" / "="
- * pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
- * / "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
- * / "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
+ * pct-encoded-unescaped = "%" ( "0" / "1" / "3" / "4" / "6" / "7" / "8" / "9" / A-to-F ) HEXDIG
+ * / "%" "2" ( "0" / "1" / "3" / "4" / "5" / "6" / "7" / "8" / "9" / A-to-F )
+ * / "%" "5" ( DIGIT / "A" / "B" / "D" / "E" / "F" )
*
- * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
+ * qchar-no-AMP-DQUOTE = qchar-unescaped / escape ( escape / quotation-mark )
*
- * escape = "\" / "%5C" ; reverse solidus U+005C
- * quotation-mark = DQUOTE / "%22"
+ * escape = "\" / "%5C" ; reverse solidus U+005C
+ * quotation-mark = DQUOTE / "%22"
*
- * ALPHA = %x41-5A / %x61-7A
- * DIGIT = %x30-39
+ * ALPHA = %x41-5A / %x61-7A
+ * DIGIT = %x30-39
* DQUOTE = %x22
*
* @param character which is checked
@@ -137,10 +138,10 @@ public class SearchTokenizer {
|| '0' <= character && character <= '9'; // case 0..9
}
- //BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
- //RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
+ // BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
+ // RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
static boolean isWhitespace(final char character) {
- //( SP / HTAB / "%20" / "%09" )
+ // ( SP / HTAB / "%20" / "%09" )
// TODO mibo: add missing whitespaces
return character == ' ' || character == '\t';
}
@@ -158,29 +159,35 @@ public class SearchTokenizer {
private static abstract class LiteralState extends State {
protected final StringBuilder literal = new StringBuilder();
+
public LiteralState(Token t) {
super(t);
}
+
public LiteralState(Token t, char c) throws SearchTokenizerException {
super(t);
init(c);
}
+
public LiteralState(Token t, String initLiteral) {
super(t);
literal.append(initLiteral);
}
+
public State allowed(char c) {
literal.append(c);
return this;
}
+
@Override
public String getLiteral() {
return literal.toString();
}
public State init(char c) throws SearchTokenizerException {
- if(isFinished()) {
- throw new SearchTokenizerException(toString() + " is already finished.");
+ if (isFinished()) {
+ throw new SearchTokenizerException(toString() + " is already finished.",
+ SearchTokenizerException.MessageKeys.ALREADY_FINISHED);
}
literal.append(c);
return this;
@@ -191,13 +198,14 @@ public class SearchTokenizer {
public SearchExpressionState() {
super(null);
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (c == CHAR_OPEN) {
return new OpenState();
} else if (isWhitespace(c)) {
return new RwsState();
- } else if(c == CHAR_CLOSE) {
+ } else if (c == CHAR_CLOSE) {
return new CloseState();
} else {
return new SearchTermState().init(c);
@@ -214,9 +222,10 @@ public class SearchTokenizer {
public SearchTermState() {
super(Token.TERM);
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
- if(c == CHAR_N) {
+ if (c == CHAR_N) {
return new NotState(c);
} else if (c == QUOTATION_MARK) {
return new SearchPhraseState(c);
@@ -225,6 +234,7 @@ public class SearchTokenizer {
}
return forbidden(c);
}
+
@Override
public State init(char c) throws SearchTokenizerException {
return nextChar(c);
@@ -234,15 +244,16 @@ public class SearchTokenizer {
private class SearchWordState extends LiteralState {
public SearchWordState(char c) throws SearchTokenizerException {
super(Token.WORD, c);
- if(!isAllowedWord(c)) {
+ if (!isAllowedWord(c)) {
forbidden(c);
}
}
+
public SearchWordState(State toConsume) throws SearchTokenizerException {
super(Token.WORD, toConsume.getLiteral());
char[] chars = literal.toString().toCharArray();
for (char aChar : chars) {
- if(!isAllowedWord(aChar)) {
+ if (!isAllowedWord(aChar)) {
forbidden(aChar);
}
}
@@ -271,7 +282,7 @@ public class SearchTokenizer {
private class SearchPhraseState extends LiteralState {
public SearchPhraseState(char c) throws SearchTokenizerException {
super(Token.PHRASE, c);
- if(c != QUOTATION_MARK) {
+ if (c != QUOTATION_MARK) {
forbidden(c);
}
}
@@ -286,7 +297,7 @@ public class SearchTokenizer {
finish();
allowed(c);
return new SearchExpressionState();
- } else if(isFinished()) {
+ } else if (isFinished()) {
return new SearchExpressionState().init(c);
}
return forbidden(c);
@@ -298,6 +309,7 @@ public class SearchTokenizer {
super(Token.OPEN);
finish();
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
finish();
@@ -323,37 +335,40 @@ public class SearchTokenizer {
private class NotState extends LiteralState {
public NotState(char c) throws SearchTokenizerException {
super(Token.NOT, c);
- if(c != CHAR_N) {
+ if (c != CHAR_N) {
forbidden(c);
}
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (literal.length() == 1 && c == CHAR_O) {
return allowed(c);
} else if (literal.length() == 2 && c == CHAR_T) {
return allowed(c);
- } else if(literal.length() == 3 && isWhitespace(c)) {
+ } else if (literal.length() == 3 && isWhitespace(c)) {
finish();
return new BeforePhraseOrWordRwsState();
}
return forbidden(c);
}
}
+
private class AndState extends LiteralState {
public AndState(char c) throws SearchTokenizerException {
super(Token.AND, c);
- if(c != CHAR_A) {
+ if (c != CHAR_A) {
forbidden(c);
}
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (literal.length() == 1 && c == CHAR_N) {
return allowed(c);
} else if (literal.length() == 2 && c == CHAR_D) {
return allowed(c);
- } else if(literal.length() == 3 && isWhitespace(c)) {
+ } else if (literal.length() == 3 && isWhitespace(c)) {
finish();
return new BeforeSearchExpressionRwsState();
} else {
@@ -361,18 +376,20 @@ public class SearchTokenizer {
}
}
}
+
private class OrState extends LiteralState {
public OrState(char c) throws SearchTokenizerException {
super(Token.OR, c);
- if(c != CHAR_O) {
+ if (c != CHAR_O) {
forbidden(c);
}
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (literal.length() == 1 && (c == CHAR_R)) {
return allowed(c);
- } else if(literal.length() == 2 && isWhitespace(c)) {
+ } else if (literal.length() == 2 && isWhitespace(c)) {
finish();
return new BeforeSearchExpressionRwsState();
} else {
@@ -381,12 +398,13 @@ public class SearchTokenizer {
}
}
- // RWS 'OR' RWS searchExpr
+ // RWS 'OR' RWS searchExpr
// RWS [ 'AND' RWS ] searchExpr
private class BeforeSearchExpressionRwsState extends State {
public BeforeSearchExpressionRwsState() {
super(null);
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (isWhitespace(c)) {
@@ -401,11 +419,12 @@ public class SearchTokenizer {
public BeforePhraseOrWordRwsState() {
super(null);
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (isWhitespace(c)) {
return allowed(c);
- } else if(c == '"') {
+ } else if (c == '"') {
return new SearchPhraseState(c);
} else {
return new SearchWordState(c);
@@ -417,6 +436,7 @@ public class SearchTokenizer {
public RwsState() {
super(null);
}
+
@Override
public State nextChar(char c) throws SearchTokenizerException {
if (isWhitespace(c)) {
@@ -438,10 +458,10 @@ public class SearchTokenizer {
* @param searchQuery search query to be tokenized
* @return list of tokens
* @throws SearchTokenizerException if something in query is not valid
- * (based on OData search query ABNF)
+ * (based on OData search query ABNF)
*/
public List<SearchQueryToken> tokenize(final String searchQuery)
- throws SearchTokenizerException {
+ throws SearchTokenizerException {
char[] chars = searchQuery.trim().toCharArray();
@@ -455,7 +475,7 @@ public class SearchTokenizer {
state = next;
}
- if(state.close().isFinished()) {
+ if (state.close().isFinished()) {
states.add(state);
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8457c0f6/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
index 451632b..fb20efe 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerException.java
@@ -18,11 +18,30 @@
*/
package org.apache.olingo.server.core.uri.parser.search;
-public class SearchTokenizerException extends Exception {
+import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+
+public class SearchTokenizerException extends UriParserSyntaxException {
private static final long serialVersionUID = -8295456415309640166L;
- public SearchTokenizerException(String message) {
- super(message);
+ public static enum MessageKeys implements MessageKey {
+ /** parameter: character */
+ FORBIDDEN_CHARACTER,
+ ALREADY_FINISHED;
+
+ @Override
+ public String getKey() {
+ return name();
+ }
+ }
+
+ public SearchTokenizerException(final String developmentMessage, final MessageKey messageKey,
+ final String... parameters) {
+ super(developmentMessage, messageKey, parameters);
+ }
+
+ public SearchTokenizerException(final String developmentMessage, final Throwable cause, final MessageKey messageKey,
+ final String... parameters) {
+ super(developmentMessage, cause, messageKey, parameters);
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8457c0f6/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
index 271b617..dd5ab70 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserAndTokenizerTest.java
@@ -33,7 +33,7 @@ import org.junit.Test;
public class SearchParserAndTokenizerTest {
@Test
- public void basicParsing() throws SearchTokenizerException {
+ public void basicParsing() throws Exception {
SearchExpressionValidator.init("a")
.validate(with("a"));
SearchExpressionValidator.init("a AND b")
@@ -172,17 +172,18 @@ public class SearchParserAndTokenizerTest {
Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
}
- private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException {
+ private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException,
+ SearchParserException {
final SearchExpression searchExpression = getSearchExpression();
Assert.assertEquals(expectedSearchExpression.toString(), searchExpression.toString());
}
- private void validate(String expectedSearchExpression) throws SearchTokenizerException {
+ private void validate(String expectedSearchExpression) throws SearchTokenizerException, SearchParserException {
final SearchExpression searchExpression = getSearchExpression();
Assert.assertEquals(expectedSearchExpression, searchExpression.toString());
}
- private SearchExpression getSearchExpression() {
+ private SearchExpression getSearchExpression() throws SearchParserException, SearchTokenizerException {
SearchParser tokenizer = new SearchParser();
SearchOption result = tokenizer.parse(null, searchQuery);
Assert.assertNotNull(result);
@@ -195,5 +196,4 @@ public class SearchParserAndTokenizerTest {
}
}
-
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8457c0f6/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 89b59b4..0902e8a 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -21,6 +21,7 @@ package org.apache.olingo.server.core.uri.parser.search;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -29,35 +30,35 @@ import java.util.List;
import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.core.uri.parser.search.SearchParserException.MessageKeys;
import org.apache.olingo.server.core.uri.parser.search.SearchQueryToken.Token;
-import org.junit.Ignore;
import org.junit.Test;
public class SearchParserTest extends SearchParser {
@Test
- public void simple() {
+ public void simple() throws Exception {
SearchExpression se = run(Token.WORD);
assertEquals("'word1'", se.toString());
assertTrue(se.isSearchTerm());
assertEquals("word1", se.asSearchTerm().getSearchTerm());
-
+
se = run(Token.PHRASE);
assertEquals("'phrase1'", se.toString());
assertTrue(se.isSearchTerm());
- //TODO: Check if quotation marks should be part of the string we deliver
+ // TODO: Check if quotation marks should be part of the string we deliver
assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
}
@Test
- public void simpleAnd() {
+ public void simpleAnd() throws Exception {
SearchExpression se = run(Token.WORD, Token.AND, Token.WORD);
assertEquals("{'word1' AND 'word2'}", se.toString());
assertTrue(se.isSearchBinary());
assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
-
+
se = run(Token.PHRASE, Token.AND, Token.PHRASE);
assertEquals("{'phrase1' AND 'phrase2'}", se.toString());
assertTrue(se.isSearchBinary());
@@ -65,16 +66,16 @@ public class SearchParserTest extends SearchParser {
assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
-
+
@Test
- public void simpleOr() {
+ public void simpleOr() throws Exception {
SearchExpression se = run(Token.WORD, Token.OR, Token.WORD);
assertEquals("{'word1' OR 'word2'}", se.toString());
assertTrue(se.isSearchBinary());
assertEquals(SearchBinaryOperatorKind.OR, se.asSearchBinary().getOperator());
assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
-
+
se = run(Token.PHRASE, Token.OR, Token.PHRASE);
assertEquals("{'phrase1' OR 'phrase2'}", se.toString());
assertTrue(se.isSearchBinary());
@@ -82,16 +83,16 @@ public class SearchParserTest extends SearchParser {
assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
-
+
@Test
- public void simpleImplicitAnd() {
+ public void simpleImplicitAnd() throws Exception {
SearchExpression se = run(Token.WORD, Token.WORD);
assertEquals("{'word1' AND 'word2'}", se.toString());
assertTrue(se.isSearchBinary());
assertEquals(SearchBinaryOperatorKind.AND, se.asSearchBinary().getOperator());
assertEquals("word1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
assertEquals("word2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
-
+
se = run(Token.PHRASE, Token.PHRASE);
assertEquals("{'phrase1' AND 'phrase2'}", se.toString());
assertTrue(se.isSearchBinary());
@@ -99,59 +100,119 @@ public class SearchParserTest extends SearchParser {
assertEquals("phrase1", se.asSearchBinary().getLeftOperand().asSearchTerm().getSearchTerm());
assertEquals("phrase2", se.asSearchBinary().getRightOperand().asSearchTerm().getSearchTerm());
}
-
+
@Test
- public void simpleBrackets() {
+ public void simpleBrackets() throws Exception {
SearchExpression se = run(Token.OPEN, Token.WORD, Token.CLOSE);
assertEquals("'word1'", se.toString());
assertTrue(se.isSearchTerm());
assertEquals("word1", se.asSearchTerm().getSearchTerm());
-
+
se = run(Token.OPEN, Token.PHRASE, Token.CLOSE);
assertEquals("'phrase1'", se.toString());
assertTrue(se.isSearchTerm());
assertEquals("phrase1", se.asSearchTerm().getSearchTerm());
}
-
+
@Test
- public void simpleNot() {
+ public void simpleNot() throws Exception {
SearchExpression se = run(Token.NOT, Token.WORD);
assertEquals("{NOT 'word1'}", se.toString());
assertTrue(se.isSearchUnary());
assertEquals("word1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
-
+
se = run(Token.NOT, Token.PHRASE);
assertEquals("{NOT 'phrase1'}", se.toString());
assertTrue(se.isSearchUnary());
assertEquals("phrase1", se.asSearchUnary().getOperand().asSearchTerm().getSearchTerm());
}
-
+
@Test
- public void precedenceLast() {
- //word1 AND (word2 AND word3)
+ public void precedenceLast() throws Exception {
+ // word1 AND (word2 AND word3)
SearchExpression se = run(Token.WORD, Token.AND, Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE);
assertEquals("{'word1' AND {'word2' AND 'word3'}}", se.toString());
}
-
+
@Test
- public void precedenceFirst() {
- //(word1 AND word2) AND word3
+ public void precedenceFirst() throws Exception {
+ // (word1 AND word2) AND word3
SearchExpression se = run(Token.OPEN, Token.WORD, Token.AND, Token.WORD, Token.CLOSE, Token.AND, Token.WORD);
assertEquals("{{'word1' AND 'word2'} AND 'word3'}", se.toString());
}
@Test
- public void combinationAndOr() {
- //word1 AND word2 OR word3
+ public void combinationAndOr() throws Exception {
+ // word1 AND word2 OR word3
SearchExpression se = run(Token.WORD, Token.AND, Token.WORD, Token.OR, Token.WORD);
assertEquals("{{'word1' AND 'word2'} OR 'word3'}", se.toString());
- //word1 OR word2 AND word3
+ // word1 OR word2 AND word3
se = run(Token.WORD, Token.OR, Token.WORD, Token.AND, Token.WORD);
assertEquals("{'word1' OR {'word2' AND 'word3'}}", se.toString());
}
+ @Test
+ public void unnecessaryBrackets() throws Exception {
+ // (word1) (word2)
+ SearchExpression se = run(Token.OPEN, Token.WORD, Token.CLOSE, Token.OPEN, Token.WORD, Token.CLOSE);
+ assertEquals("{'word1' AND 'word2'}", se.toString());
+ }
+
+ @Test
+ public void complex() throws Exception {
+ // ((word1 word2) word3) OR word4
+ SearchExpression se =
+ run(Token.OPEN, Token.OPEN, Token.WORD, Token.WORD, Token.CLOSE, Token.WORD, Token.CLOSE, Token.OR, Token.WORD);
+ assertEquals("{{{'word1' AND 'word2'} AND 'word3'} OR 'word4'}", se.toString());
+ }
+
+ @Test
+ public void doubleNot() throws Exception {
+ SearchExpression se = run(Token.NOT, Token.WORD, Token.AND, Token.NOT, Token.PHRASE);
+ assertEquals("{{NOT 'word1'} AND {NOT 'phrase1'}}", se.toString());
+ }
+
+ @Test
+ public void notAnd() throws Exception {
+ runEx(SearchParserException.MessageKeys.INVALID_NOT_OPERAND, Token.NOT, Token.AND);
+ }
+
+ @Test
+ public void doubleAnd() throws Exception {
+ runEx(SearchParserException.MessageKeys.INVALID_OPERATOR_AFTER_AND, Token.WORD, Token.AND, Token.AND, Token.WORD);
+ }
+
+ @Test
+ public void singleAnd() {
+ runEx(SearchParserException.MessageKeys.INVALID_BINARY_OPERATOR_POSITION, Token.AND);
+ }
+
+ @Test
+ public void singleOpenBracket() {
+ runEx(SearchParserException.MessageKeys.EXPECTED_DIFFERENT_TOKEN, Token.OPEN);
+ }
+
+ @Test
+ public void emptyBrackets() {
+ runEx(SearchParserException.MessageKeys.NO_EXPRESSION_FOUND, Token.OPEN, Token.CLOSE);
+ }
+
+ @Test
+ public void empty() {
+ Token[] emptyArray = new Token[0];
+ runEx(SearchParserException.MessageKeys.NO_EXPRESSION_FOUND, emptyArray);
+ }
+
+ private void runEx(MessageKeys key, Token... tokenArray) {
+ try {
+ run(tokenArray);
+ fail("Expected UriParserSyntaxException with key " + key);
+ } catch (SearchParserException e) {
+ assertEquals(key, e.getMessageKey());
+ }
+ }
- private SearchExpression run(SearchQueryToken.Token... tokenArray) {
+ private SearchExpression run(SearchQueryToken.Token... tokenArray) throws SearchParserException {
List<SearchQueryToken> tokenList = prepareTokens(tokenArray);
SearchExpression se = parseInternal(tokenList);
assertNotNull(se);
@@ -172,6 +233,7 @@ public class SearchParserTest extends SearchParser {
when(token.getLiteral()).thenReturn("phrase" + phraseNumber);
phraseNumber++;
}
+ when(token.toString()).thenReturn("" + tokenArray[i]);
tokenList.add(token);
}
return tokenList;
[07/23] olingo-odata4 git commit: [OLINGO-568] Removed not necessary
code and enums
Posted by mi...@apache.org.
[OLINGO-568] Removed not necessary code and enums
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/96483ae5
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/96483ae5
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/96483ae5
Branch: refs/heads/master
Commit: 96483ae559ea8d9dc0624b68876a4045102ba659
Parents: 43bc49f
Author: mibo <mi...@apache.org>
Authored: Mon Nov 9 20:33:05 2015 +0100
Committer: mibo <mi...@apache.org>
Committed: Mon Nov 9 20:33:05 2015 +0100
----------------------------------------------------------------------
.../uri/parser/search/SearchQueryToken.java | 2 +-
.../core/uri/parser/search/SearchTokenizer.java | 61 +++++++-------------
.../uri/parser/search/SearchTokenizerTest.java | 21 ++++---
3 files changed, 36 insertions(+), 48 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/96483ae5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
index a08c1a2..eb1a009 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchQueryToken.java
@@ -19,7 +19,7 @@
package org.apache.olingo.server.core.uri.parser.search;
public interface SearchQueryToken {
- enum Token {OPEN, BWS, RWS, TERM, SEARCH_EXPRESSION, NOT, AND, OR, WORD, PHRASE, CLOSE}
+ enum Token {OPEN, TERM, NOT, AND, OR, WORD, PHRASE, CLOSE}
Token getToken();
String getLiteral();
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/96483ae5/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
index f62e0f4..12af609 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizer.java
@@ -44,7 +44,6 @@ public class SearchTokenizer {
private Token token = null;
private boolean finished = false;
- protected static final char EOF = 0x03;
protected static final char QUOTATION_MARK = '\"';
protected static final char CHAR_N = 'N';
protected static final char CHAR_O = 'O';
@@ -82,8 +81,8 @@ public class SearchTokenizer {
return token;
}
- public boolean close() {
- return nextChar(EOF).isFinished();
+ public State close() {
+ return this;
}
static boolean isAllowedChar(final char character) {
@@ -114,10 +113,6 @@ public class SearchTokenizer {
|| character == '=';
}
- static boolean isEof(final char character) {
- return character == EOF;
- }
-
//BWS = *( SP / HTAB / "%20" / "%09" ) ; "bad" whitespace
//RWS = 1*( SP / HTAB / "%20" / "%09" ) ; "required" whitespace
static boolean isWhitespace(final char character) {
@@ -138,7 +133,7 @@ public class SearchTokenizer {
}
private static abstract class LiteralState extends State {
- private final StringBuilder literal = new StringBuilder();
+ protected final StringBuilder literal = new StringBuilder();
public LiteralState(Token t) {
super(t);
}
@@ -170,7 +165,7 @@ public class SearchTokenizer {
private class SearchExpressionState extends LiteralState {
public SearchExpressionState() {
- super(Token.SEARCH_EXPRESSION);
+ super(null);
}
@Override
public State nextChar(char c) {
@@ -180,19 +175,12 @@ public class SearchTokenizer {
return new RwsImplicitAndState();
} else if(c == CHAR_CLOSE) {
return new CloseState();
- } else if(isWhitespace(c)) {
- return new AndState(c);
} else {
return new SearchTermState().init(c);
}
}
@Override
- public boolean close() {
- return true;
- }
-
- @Override
public State init(char c) {
return nextChar(c);
}
@@ -237,11 +225,14 @@ public class SearchTokenizer {
} else if (isWhitespace(c)) {
finish();
return new RwsImplicitAndState();
- } else if (isEof(c)) {
- return finish();
}
return forbidden(c);
}
+
+ @Override
+ public State close() {
+ return finish();
+ }
}
private class SearchPhraseState extends LiteralState {
@@ -254,7 +245,7 @@ public class SearchTokenizer {
@Override
public State nextChar(char c) {
- if(isFinished() && !isEof(c)) {
+ if(isFinished()) {
return new SearchExpressionState().init(c);
} else if (isAllowedPhrase(c)) {
return allowed(c);
@@ -272,8 +263,6 @@ public class SearchTokenizer {
return new CloseState();
}
return allowed(c);
- } else if (isEof(c)) {
- return finish();
}
return forbidden(c);
}
@@ -302,11 +291,7 @@ public class SearchTokenizer {
@Override
public State nextChar(char c) {
- if (isEof(c)) {
- return finish();
- } else {
- return new SearchExpressionState().init(c);
- }
+ return new SearchExpressionState().init(c);
}
}
@@ -319,9 +304,9 @@ public class SearchTokenizer {
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && (c == CHAR_O)) {
+ if (getLiteral().length() == 1 && c == CHAR_O) {
return allowed(c);
- } else if (getLiteral().length() == 2 && (c == CHAR_T)) {
+ } else if (getLiteral().length() == 2 && c == CHAR_T) {
return allowed(c);
} else if(getLiteral().length() == 3 && isWhitespace(c)) {
finish();
@@ -341,11 +326,11 @@ public class SearchTokenizer {
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && (c == CHAR_N)) {
+ if (literal.length() == 1 && c == CHAR_N) {
return allowed(c);
- } else if (getLiteral().length() == 2 && (c == CHAR_D)) {
+ } else if (literal.length() == 2 && c == CHAR_D) {
return allowed(c);
- } else if(getLiteral().length() == 3 && isWhitespace(c)) {
+ } else if(literal.length() == 3 && isWhitespace(c)) {
finish();
return new BeforeSearchExpressionRwsState();
} else {
@@ -363,9 +348,9 @@ public class SearchTokenizer {
}
@Override
public State nextChar(char c) {
- if (getLiteral().length() == 1 && (c == CHAR_R)) {
+ if (literal.length() == 1 && (c == CHAR_R)) {
return allowed(c);
- } else if(getLiteral().length() == 2 && isWhitespace(c)) {
+ } else if(literal.length() == 2 && isWhitespace(c)) {
finish();
return new BeforeSearchExpressionRwsState();
} else {
@@ -378,7 +363,7 @@ public class SearchTokenizer {
// RWS [ 'AND' RWS ] searchExpr
private class BeforeSearchExpressionRwsState extends State {
public BeforeSearchExpressionRwsState() {
- super(Token.RWS);
+ super(null);
}
@Override
public State nextChar(char c) {
@@ -424,12 +409,8 @@ public class SearchTokenizer {
state = next;
}
- if(state.close()) {
- if(state.isFinished()) {
- states.add(state);
- }
- } else {
- throw new IllegalStateException("State: " + state + " not finished and list is: " + states.toString());
+ if(state.close().isFinished()) {
+ states.add(state);
}
return states;
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/96483ae5/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
index e53b6b2..29287cd 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchTokenizerTest.java
@@ -287,15 +287,22 @@ public class SearchTokenizerTest {
Assert.assertEquals(AND, it.next().getToken());
Assert.assertEquals(WORD, it.next().getToken());
- result = tokenizer.tokenize("abc OR orsomething");
- log(result.toString());
- it = result.iterator();
- Assert.assertEquals(WORD, it.next().getToken());
- Assert.assertEquals(OR, it.next().getToken());
- Assert.assertEquals(WORD, it.next().getToken());
-
SearchValidator.init("abc AND ANDsomething")
.addExpected(WORD, AND, WORD).validate();
+
+ // FIXME (mibo): issue with implicit and
+// SearchValidator.init("abc ANDsomething").enableLogging()
+// .addExpected(WORD, AND, WORD).validate();
+
+// SearchValidator.init("abc ORsomething")
+// .addExpected(WORD, AND, WORD).validate();
+
+ SearchValidator.init("abc OR orsomething")
+ .addExpected(WORD, OR, WORD).validate();
+
+ SearchValidator.init("abc OR ORsomething")
+ .addExpected(WORD, OR, WORD).validate();
+
}
@Test
[10/23] olingo-odata4 git commit: [OLINGO-568] Added Search*Impl
classes
Posted by mi...@apache.org.
[OLINGO-568] Added Search*Impl classes
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/37c5827f
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/37c5827f
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/37c5827f
Branch: refs/heads/master
Commit: 37c5827f9343bfc7554d3bb63bdcf96c14da0cd9
Parents: 3eef0bf
Author: Michael Bolz <mi...@sap.com>
Authored: Wed Nov 11 12:48:09 2015 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Wed Nov 11 12:48:09 2015 +0100
----------------------------------------------------------------------
.../api/uri/queryoption/search/SearchUnary.java | 5 +-
.../uri/parser/search/SearchBinaryImpl.java | 56 ++++++++
.../core/uri/parser/search/SearchParser.java | 93 +++++++++++-
.../core/uri/parser/search/SearchTermImpl.java | 39 +++++
.../core/uri/parser/search/SearchUnaryImpl.java | 46 ++++++
.../uri/parser/search/SearchParserTest.java | 143 ++++++++++++++++++-
6 files changed, 373 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/37c5827f/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
index 5d8e143..c266308 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/search/SearchUnary.java
@@ -18,8 +18,9 @@
*/
package org.apache.olingo.server.api.uri.queryoption.search;
-public interface SearchUnary {
+public interface SearchUnary extends SearchExpression {
- SearchExpression getOperand();
+ SearchUnaryOperatorKind getOperator();
+ SearchTerm getOperand();
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/37c5827f/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
new file mode 100644
index 0000000..37b03c0
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchBinaryImpl.java
@@ -0,0 +1,56 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinary;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+
+public class SearchBinaryImpl implements SearchBinary {
+
+ private final SearchBinaryOperatorKind operator;
+ private final SearchExpression left;
+ private final SearchExpression right;
+
+ public SearchBinaryImpl(SearchExpression left, SearchBinaryOperatorKind operator, SearchExpression right) {
+ this.left = left;
+ this.operator = operator;
+ this.right = right;
+ }
+
+ @Override
+ public SearchBinaryOperatorKind getOperator() {
+ return operator;
+ }
+
+ @Override
+ public SearchExpression getLeftOperand() {
+ return left;
+ }
+
+ @Override
+ public SearchExpression getRightOperand() {
+ return right;
+ }
+
+ @Override
+ public String toString() {
+ return "{" + left + " " + operator.name() + " " + right + '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/37c5827f/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
index ca45037..60fcd4b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchParser.java
@@ -19,19 +19,106 @@
package org.apache.olingo.server.core.uri.parser.search;
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
import org.apache.olingo.server.core.uri.queryoption.SearchOptionImpl;
-import java.util.List;
+import java.util.Iterator;
public class SearchParser {
+ private Iterator<SearchQueryToken> tokens;
+ private SearchExpression root;
+// private SearchQueryToken currentToken;
+
public SearchOption parse(String path, String value) {
SearchTokenizer tokenizer = new SearchTokenizer();
try {
- List<SearchQueryToken> tokens = tokenizer.tokenize(value);
+ tokens = tokenizer.tokenize(value).iterator();
+// currentToken = tokens.next();
+ root = processSearchExpression();
} catch (SearchTokenizerException e) {
return null;
}
- return new SearchOptionImpl();
+ final SearchOptionImpl searchOption = new SearchOptionImpl();
+ searchOption.setSearchExpression(root);
+ return searchOption;
+ }
+
+ private SearchExpression processSearchExpression() {
+ SearchQueryToken token = nextToken();
+ if(token.getToken() == SearchQueryToken.Token.OPEN) {
+ throw illegalState();
+ } else if(token.getToken() == SearchQueryToken.Token.NOT) {
+ return processNot();
+ } else if(token.getToken() == SearchQueryToken.Token.PHRASE ||
+ token.getToken() == SearchQueryToken.Token.WORD) {
+ return processTerm(token);
+// } else if(token.getToken() == SearchQueryToken.Token.AND) {
+// return processAnd();
+ } else {
+ throw illegalState();
+ }
+ }
+
+ private SearchExpression processAnd(SearchExpression se) {
+ SearchQueryToken token = nextToken();
+ if(token.getToken() == SearchQueryToken.Token.PHRASE ||
+ token.getToken() == SearchQueryToken.Token.WORD) {
+// SearchExpression t = processTerm(token);
+ return new SearchBinaryImpl(se, SearchBinaryOperatorKind.AND, processTerm(token));
+ }
+ throw illegalState();
+ }
+
+ private SearchExpression processOr(SearchExpression se) {
+ SearchQueryToken token = nextToken();
+ if(token.getToken() == SearchQueryToken.Token.PHRASE ||
+ token.getToken() == SearchQueryToken.Token.WORD) {
+ return new SearchBinaryImpl(se, SearchBinaryOperatorKind.OR, processTerm(token));
+ }
+ throw illegalState();
+ }
+
+ private RuntimeException illegalState() {
+ return new RuntimeException();
+ }
+
+ private SearchUnaryImpl processNot() {
+ SearchQueryToken token = nextToken();
+ if(token.getToken() == SearchQueryToken.Token.PHRASE ||
+ token.getToken() == SearchQueryToken.Token.WORD) {
+ throw illegalState();
+// return new SearchUnaryImpl(processTerm(token));
+ }
+ throw illegalState();
+ }
+
+ private SearchQueryToken nextToken() {
+// if(tokens.hasNext()) {
+ return tokens.next();
+// }
+// return null;
+ }
+
+ private SearchExpression processTerm(SearchQueryToken token) {
+ SearchTerm searchTerm = new SearchTermImpl(token.getLiteral());
+ if(isEof()) {
+ return searchTerm;
+ }
+
+ SearchQueryToken next = nextToken();
+ if(next.getToken() == SearchQueryToken.Token.AND) {
+ return processAnd(searchTerm);
+ } else if(next.getToken() == SearchQueryToken.Token.OR) {
+ return processOr(searchTerm);
+ }
+
+ throw illegalState();
+ }
+
+ private boolean isEof() {
+ return !tokens.hasNext();
}
}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/37c5827f/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
new file mode 100644
index 0000000..24b1291
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchTermImpl.java
@@ -0,0 +1,39 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
+
+public class SearchTermImpl implements SearchTerm {
+ private final String term;
+
+ public SearchTermImpl(String term) {
+ this.term = term;
+ }
+
+ @Override
+ public String getSearchTerm() {
+ return term;
+ }
+
+ @Override
+ public String toString() {
+ return "{'" + term + "'}";
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/37c5827f/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
new file mode 100644
index 0000000..639540d
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/search/SearchUnaryImpl.java
@@ -0,0 +1,46 @@
+/*
+ * 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
+ *
+ * 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 org.apache.olingo.server.core.uri.parser.search;
+
+import org.apache.olingo.server.api.uri.queryoption.search.SearchTerm;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchUnaryOperatorKind;
+
+public class SearchUnaryImpl implements SearchUnary {
+ private final SearchTerm operand;
+
+ public SearchUnaryImpl(SearchTerm operand) {
+ this.operand = operand;
+ }
+
+ @Override
+ public SearchUnaryOperatorKind getOperator() {
+ return SearchUnaryOperatorKind.NOT;
+ }
+
+ @Override
+ public SearchTerm getOperand() {
+ return operand;
+ }
+
+ @Override
+ public String toString() {
+ return "{" + getOperator().name() + " " + operand + '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/37c5827f/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
index 0c51ba6..fa42293 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/uri/parser/search/SearchParserTest.java
@@ -20,14 +20,149 @@ package org.apache.olingo.server.core.uri.parser.search;
import org.apache.olingo.server.api.uri.queryoption.SearchOption;
import org.apache.olingo.server.api.uri.queryoption.search.SearchExpression;
+import org.apache.olingo.server.api.uri.queryoption.search.SearchUnary;
+import org.junit.Assert;
+import org.junit.Ignore;
import org.junit.Test;
+import java.lang.reflect.Field;
+
+import static org.apache.olingo.server.api.uri.queryoption.search.SearchBinaryOperatorKind.*;
+
public class SearchParserTest {
@Test
- public void basicParsing() {
- SearchParser parser = new SearchParser();
- SearchOption so = parser.parse("ESAllPrim", "abc");
- SearchExpression se = so.getSearchExpression();
+ public void basicParsing() throws SearchTokenizerException {
+ SearchExpressionValidator.init("a")
+ .validate(with("a"));
+ SearchExpressionValidator.init("a AND b")
+ .validate(with("a", and("b")));
+ SearchExpressionValidator.init("a AND b AND c")
+ .validate(with("a", and("b", and("c"))));
+ SearchExpressionValidator.init("a OR b")
+ .validate(with("a", or("b")));
+ SearchExpressionValidator.init("a OR b OR c")
+ .validate(with("a", or("b", or("c"))));
+ }
+
+ @Test
+ @Ignore("Currently not working")
+ public void mixedParsing() throws Exception{
+ SearchExpressionValidator.init("a AND b OR c")
+ .validate(with("c", or("a", and("b"))));
+ }
+
+ @Test
+ @Ignore("Internal test, to be deleted")
+ public void sebuilder() {
+ System.out.println(with("c", or("a", and("b"))).toString());
+ System.out.println(with("a", and("b", and("c"))).toString());
+ System.out.println(with("a").toString());
+ System.out.println(with(not("a")).toString());
+ System.out.println(with("a", and("b")).toString());
+ System.out.println(with("a", or("b")).toString());
+ System.out.println(with("a", and(not("b"))).toString());
+ }
+
+ private static SearchExpression with(String term) {
+ return new SearchTermImpl(term);
+ }
+
+
+ private static SearchExpression with(String left, SearchExpression right) {
+ setLeftField(left, right);
+ return right;
+ }
+
+ private static SearchUnary with(SearchUnary unary) {
+ return unary;
+ }
+
+ private static SearchExpression or(String left, SearchExpression right) {
+ SearchExpression or = or(right);
+ setLeftField(left, right);
+ return or;
+ }
+
+ private static SearchExpression and(String left, SearchExpression right) {
+ SearchExpression and = and(right);
+ setLeftField(left, right);
+ return and;
}
+
+ private static SearchExpression or(SearchExpression right) {
+ return new SearchBinaryImpl(null, OR, right);
+ }
+
+ private static SearchExpression and(SearchExpression right) {
+ return new SearchBinaryImpl(null, AND, right);
+ }
+
+ private static SearchExpression and(String right) {
+ return and(new SearchTermImpl(right));
+ }
+
+ private static SearchExpression or(String right) {
+ return or(new SearchTermImpl(right));
+ }
+
+ private static SearchUnary not(String term) {
+ return new SearchUnaryImpl(new SearchTermImpl(term));
+ }
+
+ private static void setLeftField(String left, SearchExpression se) {
+ try {
+ Field field = null;
+ if(se instanceof SearchUnaryImpl) {
+ field = SearchBinaryImpl.class.getDeclaredField("operand");
+ } else if(se instanceof SearchBinaryImpl) {
+ field = SearchBinaryImpl.class.getDeclaredField("left");
+ } else {
+ Assert.fail("Unexpected exception: " + se.getClass());
+ }
+ field.setAccessible(true);
+ field.set(se, new SearchTermImpl(left));
+ } catch (Exception e) {
+ Assert.fail("Unexpected exception: " + e.getClass());
+ }
+ }
+
+ private static class SearchExpressionValidator {
+ private boolean log;
+ private final String searchQuery;
+
+ private SearchExpressionValidator(String searchQuery) {
+ this.searchQuery = searchQuery;
+ }
+
+ private static SearchExpressionValidator init(String searchQuery) {
+ return new SearchExpressionValidator(searchQuery);
+ }
+ private SearchExpressionValidator enableLogging() {
+ log = true;
+ return this;
+ }
+ private void validate(Class<? extends Exception> exception) throws SearchTokenizerException {
+ try {
+ new SearchTokenizer().tokenize(searchQuery);
+ } catch (Exception e) {
+ Assert.assertEquals(exception, e.getClass());
+ return;
+ }
+ Assert.fail("Expected exception " + exception.getClass().getSimpleName() + " was not thrown.");
+ }
+
+ private void validate(SearchExpression expectedSearchExpression) throws SearchTokenizerException {
+ SearchParser tokenizer = new SearchParser();
+ SearchOption result = tokenizer.parse(null, searchQuery);
+ Assert.assertNotNull(result);
+ final SearchExpression searchExpression = result.getSearchExpression();
+ Assert.assertNotNull(searchExpression);
+ if(log) {
+ System.out.println(expectedSearchExpression);
+ }
+ Assert.assertEquals(expectedSearchExpression.toString(), searchExpression.toString());
+ }
+ }
+
}
\ No newline at end of file