mirror of
https://github.com/apache/olingo-odata4.git
synced 2025-02-07 02:29:18 +00:00
Merge remote-tracking branch 'origin/OLINGO-834_RefactorUriParsing' into OLINGO-834_Filter_Parser
This commit is contained in:
commit
ef19c9be1f
@ -245,7 +245,7 @@ public class BasicITCase extends AbstractParamTecSvcITCase {
|
||||
} catch (final ODataClientErrorException e) {
|
||||
assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode());
|
||||
final ODataError error = e.getODataError();
|
||||
assertThat(error.getMessage(), containsString("key property"));
|
||||
assertThat(error.getMessage(), containsString("key"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,19 +133,19 @@ public class EdmBinary extends SingletonPrimitiveType {
|
||||
final Boolean isNullable, final Integer maxLength, final Integer precision,
|
||||
final Integer scale, final Boolean isUnicode) {
|
||||
|
||||
return value == null
|
||||
? isNullable == null || isNullable
|
||||
: isBase64(value.getBytes(UTF_8)) && validateMaxLength(value, maxLength);
|
||||
return value == null ?
|
||||
isNullable == null || isNullable :
|
||||
isBase64(value.getBytes(UTF_8)) && validateMaxLength(value, maxLength);
|
||||
}
|
||||
|
||||
private static boolean validateMaxLength(final String value, final Integer maxLength) {
|
||||
return maxLength == null ? true
|
||||
: // Every three bytes are represented as four base-64 characters.
|
||||
return maxLength == null ? true :
|
||||
// Every three bytes are represented as four base-64 characters.
|
||||
// Additionally, there could be up to two padding "=" characters
|
||||
// if the number of bytes is not a multiple of three,
|
||||
// and there could be line feeds, possibly with carriage returns.
|
||||
maxLength >= (value.length() - lineEndingsLength(value)) * 3 / 4
|
||||
- (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0);
|
||||
- (value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0);
|
||||
}
|
||||
|
||||
private static int lineEndingsLength(final String value) {
|
||||
|
@ -96,7 +96,7 @@ public class EdmActionImportImplTest {
|
||||
String target = "nonExisting";
|
||||
CsdlActionImport providerActionImport = new CsdlActionImport().setName("actionImportName").setEntitySet(target);
|
||||
EdmProviderImpl edm = mock(EdmProviderImpl.class);
|
||||
when(edm.getEntityContainer(null)).thenReturn(container);
|
||||
when(edm.getEntityContainer()).thenReturn(container);
|
||||
EdmActionImport actionImport = new EdmActionImportImpl(edm, container, providerActionImport);
|
||||
actionImport.getReturnedEntitySet();
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ public class EdmProviderImplTest {
|
||||
when(localProvider.getAliasInfos()).thenThrow(new ODataException("msg"));
|
||||
|
||||
Edm localEdm = new EdmProviderImpl(localProvider);
|
||||
localEdm.getEntityContainer(null);
|
||||
localEdm.getEntityContainer();
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -193,7 +193,7 @@ public class EdmProviderImplTest {
|
||||
assertEquals(FQN.getNamespace(), entityContainer.getNamespace());
|
||||
assertEquals(FQN.getName(), entityContainer.getName());
|
||||
|
||||
entityContainer = edm.getEntityContainer(null);
|
||||
entityContainer = edm.getEntityContainer();
|
||||
assertNotNull(entityContainer);
|
||||
assertEquals(FQN.getNamespace(), entityContainer.getNamespace());
|
||||
assertEquals(FQN.getName(), entityContainer.getName());
|
||||
|
@ -229,6 +229,7 @@ public class EdmSchemaImplTest {
|
||||
|
||||
assertTrue(container == edm.getEntityContainer(new FullQualifiedName(schema.getNamespace(), container.getName())));
|
||||
assertTrue(container == edm.getEntityContainer(null));
|
||||
assertTrue(container == edm.getEntityContainer());
|
||||
}
|
||||
|
||||
private class LocalProvider implements CsdlEdmProvider {
|
||||
|
@ -90,13 +90,15 @@ public class ErrorHandler {
|
||||
final ODataServerError serverError) {
|
||||
ContentType requestedContentType;
|
||||
try {
|
||||
UriInfo uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(),
|
||||
null, this.metadata.getEdm());
|
||||
final UriInfo uriInfo = new Parser(metadata.getEdm(), odata)
|
||||
.parseUri(request.getRawODataPath(), request.getRawQueryPath(), null);
|
||||
requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
|
||||
request, this.customContent, RepresentationType.ERROR);
|
||||
} catch (final ContentNegotiatorException e) {
|
||||
requestedContentType = ContentType.JSON;
|
||||
} catch (UriParserException e) {
|
||||
} catch (final UriParserException e) {
|
||||
requestedContentType = ContentType.JSON;
|
||||
} catch (final UriValidationException e) {
|
||||
requestedContentType = ContentType.JSON;
|
||||
}
|
||||
processError(response, serverError, requestedContentType);
|
||||
|
@ -76,8 +76,8 @@ public class ServiceDispatcher extends RequestURLHierarchyVisitor {
|
||||
public void execute(ODataRequest odRequest, ODataResponse odResponse)
|
||||
throws ODataLibraryException, ODataApplicationException {
|
||||
|
||||
UriInfo uriInfo = new Parser().parseUri(odRequest.getRawODataPath(), odRequest.getRawQueryPath(), null,
|
||||
this.metadata.getEdm());
|
||||
UriInfo uriInfo = new Parser(this.metadata.getEdm(), odata)
|
||||
.parseUri(odRequest.getRawODataPath(), odRequest.getRawQueryPath(), null);
|
||||
|
||||
new UriValidator().validate(uriInfo, odRequest.getMethod());
|
||||
|
||||
|
@ -47,6 +47,7 @@ import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.core.requests.DataRequest;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
|
||||
public abstract class ServiceRequest {
|
||||
protected OData odata;
|
||||
@ -240,7 +241,7 @@ public abstract class ServiceRequest {
|
||||
return null;
|
||||
}
|
||||
|
||||
public DataRequest parseLink(URI uri) throws UriParserException, URISyntaxException {
|
||||
public DataRequest parseLink(URI uri) throws UriParserException, UriValidationException, URISyntaxException {
|
||||
String path = "/";
|
||||
URI servicePath = new URI(getODataRequest().getRawBaseUri());
|
||||
path = servicePath.getPath();
|
||||
@ -253,8 +254,7 @@ public abstract class ServiceRequest {
|
||||
rawPath = rawPath.substring(e+path.length());
|
||||
}
|
||||
|
||||
UriInfo uriInfo = new Parser().parseUri(rawPath, uri.getQuery(), null,
|
||||
this.serviceMetadata.getEdm());
|
||||
UriInfo uriInfo = new Parser(serviceMetadata.getEdm(), odata).parseUri(rawPath, uri.getQuery(), null);
|
||||
ServiceDispatcher dispatcher = new ServiceDispatcher(odata, serviceMetadata, null, customContentType);
|
||||
dispatcher.visit(uriInfo);
|
||||
return (DataRequest)dispatcher.request;
|
||||
|
@ -129,8 +129,8 @@ public class ODataHandler {
|
||||
|
||||
final int measurementUriParser = debugger.startRuntimeMeasurement("UriParser", "parseUri");
|
||||
try {
|
||||
uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(), null,
|
||||
serviceMetadata.getEdm());
|
||||
uriInfo = new Parser(serviceMetadata.getEdm(), odata)
|
||||
.parseUri(request.getRawODataPath(), request.getRawQueryPath(), null);
|
||||
} catch (final ODataLibraryException e) {
|
||||
debugger.stopRuntimeMeasurement(measurementUriParser);
|
||||
debugger.stopRuntimeMeasurement(measurementHandle);
|
||||
|
@ -29,6 +29,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmStructuredType;
|
||||
import org.apache.olingo.commons.core.Encoder;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException;
|
||||
import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
@ -39,9 +40,9 @@ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
||||
import org.apache.olingo.server.api.uri.UriResourceKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.core.ODataImpl;
|
||||
import org.apache.olingo.server.core.serializer.utils.ContextURLHelper;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
|
||||
public class UriHelperImpl implements UriHelper {
|
||||
|
||||
@ -107,8 +108,8 @@ public class UriHelperImpl implements UriHelper {
|
||||
oDataPath = oDataPath.startsWith("/") ? oDataPath : "/" + oDataPath;
|
||||
|
||||
try {
|
||||
final List<UriResource> uriResourceParts = new Parser().parseUri(oDataPath, null, null, edm)
|
||||
.getUriResourceParts();
|
||||
final List<UriResource> uriResourceParts =
|
||||
new Parser(edm, new ODataImpl()).parseUri(oDataPath, null, null).getUriResourceParts();
|
||||
if (uriResourceParts.size() == 1 && uriResourceParts.get(0).getKind() == UriResourceKind.entitySet) {
|
||||
final UriResourceEntitySet entityUriResource = (UriResourceEntitySet) uriResourceParts.get(0);
|
||||
|
||||
@ -117,7 +118,7 @@ public class UriHelperImpl implements UriHelper {
|
||||
|
||||
throw new DeserializerException("Invalid entity binding link", MessageKeys.INVALID_ENTITY_BINDING_LINK,
|
||||
entityId);
|
||||
} catch (UriParserException e) {
|
||||
} catch (final ODataLibraryException e) {
|
||||
throw new DeserializerException("Invalid entity binding link", e, MessageKeys.INVALID_ENTITY_BINDING_LINK,
|
||||
entityId);
|
||||
}
|
||||
|
@ -49,10 +49,7 @@ public class UriResourceNavigationPropertyImpl extends UriResourceWithKeysImpl i
|
||||
|
||||
@Override
|
||||
public boolean isCollection() {
|
||||
if (keyPredicates != null) {
|
||||
return false;
|
||||
}
|
||||
return navigationProperty.isCollection();
|
||||
return navigationProperty.isCollection() && keyPredicates == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.apache.olingo.server.core.uri;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@ -48,7 +47,7 @@ public abstract class UriResourceWithKeysImpl extends UriResourceImpl implements
|
||||
public List<UriParameter> getKeyPredicates() {
|
||||
return keyPredicates == null ?
|
||||
Collections.<UriParameter> emptyList() :
|
||||
new ArrayList<UriParameter>(keyPredicates);
|
||||
Collections.unmodifiableList(keyPredicates);
|
||||
}
|
||||
|
||||
public UriResourceWithKeysImpl setKeyPredicates(final List<UriParameter> list) {
|
||||
|
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.apache.olingo.server.core.uri.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.antlr.v4.runtime.ANTLRInputStream;
|
||||
@ -31,11 +30,15 @@ import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.atn.PredictionMode;
|
||||
import org.antlr.v4.runtime.misc.ParseCancellationException;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourceAction;
|
||||
import org.apache.olingo.server.api.uri.UriResourceCount;
|
||||
import org.apache.olingo.server.api.uri.UriResourceFunction;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
|
||||
import org.apache.olingo.server.api.uri.UriResourceRef;
|
||||
import org.apache.olingo.server.api.uri.UriResourceValue;
|
||||
@ -46,18 +49,14 @@ import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
|
||||
import org.apache.olingo.server.core.uri.UriInfoImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceStartingTypeFilterImpl;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriLexer;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.AllEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.BatchEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.CrossjoinEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.EntityEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.ExpandItemsEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.FilterExpressionEOFContext;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser.MetadataEOFContext;
|
||||
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.UriTokenizer.TokenKind;
|
||||
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;
|
||||
@ -71,6 +70,7 @@ import org.apache.olingo.server.core.uri.queryoption.SelectOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.SkipOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.SkipTokenOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.TopOptionImpl;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
|
||||
public class Parser {
|
||||
private static final String ATOM = "atom";
|
||||
@ -78,19 +78,22 @@ public class Parser {
|
||||
private static final String XML = "xml";
|
||||
private static final String AT = "@";
|
||||
private static final String NULL = "null";
|
||||
|
||||
int logLevel = 0;
|
||||
private final Edm edm;
|
||||
private final OData odata;
|
||||
|
||||
private enum ParserEntryRules {
|
||||
All, Batch, CrossJoin, Entity, ExpandItems, FilterExpression, Metadata, PathSegment, Orderby, Select, Search
|
||||
ExpandItems, FilterExpression, Orderby, Select
|
||||
}
|
||||
|
||||
public Parser setLogLevel(final int logLevel) {
|
||||
this.logLevel = logLevel;
|
||||
return this;
|
||||
public Parser(final Edm edm, final OData odata) {
|
||||
this.edm = edm;
|
||||
this.odata = odata;
|
||||
}
|
||||
|
||||
public UriInfo parseUri(final String path, final String query, final String fragment, final Edm edm)
|
||||
throws UriParserException {
|
||||
public UriInfo parseUri(final String path, final String query, final String fragment)
|
||||
throws UriParserException, UriValidationException {
|
||||
|
||||
UriContext context = new UriContext();
|
||||
UriParseTreeVisitor uriParseTreeVisitor = new UriParseTreeVisitor(edm, context);
|
||||
@ -104,65 +107,74 @@ public class Parser {
|
||||
if (firstSegment.isEmpty()) {
|
||||
ensureLastSegment(firstSegment, 0, uri.pathSegmentListDecoded.size());
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.service);
|
||||
} else if (firstSegment.startsWith("$batch")) {
|
||||
|
||||
} else if (firstSegment.equals("$batch")) {
|
||||
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
|
||||
BatchEOFContext ctxBatchEOF =
|
||||
(BatchEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.Batch);
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.batch);
|
||||
|
||||
uriParseTreeVisitor.visitBatchEOF(ctxBatchEOF);
|
||||
} else if (firstSegment.startsWith("$metadata")) {
|
||||
} else if (firstSegment.equals("$metadata")) {
|
||||
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
|
||||
MetadataEOFContext ctxMetadataEOF =
|
||||
(MetadataEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.Metadata);
|
||||
|
||||
uriParseTreeVisitor.visitMetadataEOF(ctxMetadataEOF);
|
||||
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.metadata);
|
||||
context.contextUriInfo.setFragment(uri.fragment);
|
||||
} else if (firstSegment.startsWith("$entity")) {
|
||||
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
|
||||
} else if (firstSegment.equals("$all")) {
|
||||
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.all);
|
||||
|
||||
} else if (firstSegment.equals("$entity")) {
|
||||
if (uri.pathSegmentListDecoded.size() > 1) {
|
||||
final String typeCastSegment = uri.pathSegmentListDecoded.get(1);
|
||||
ensureLastSegment(typeCastSegment, 2, uri.pathSegmentListDecoded.size());
|
||||
EntityEOFContext ctxEntityEOF =
|
||||
(EntityEOFContext) parseRule(typeCastSegment, ParserEntryRules.Entity);
|
||||
uriParseTreeVisitor.visitEntityEOF(ctxEntityEOF);
|
||||
context.contextUriInfo = new ResourcePathParser(edm, odata).parseDollarEntityTypeCast(typeCastSegment);
|
||||
context.contextTypes.push(
|
||||
uriParseTreeVisitor.new TypeInformation(context.contextUriInfo.getEntityTypeCast(), false));
|
||||
} else {
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
|
||||
}
|
||||
|
||||
} else if (firstSegment.startsWith("$all")) {
|
||||
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
|
||||
AllEOFContext ctxResourcePathEOF =
|
||||
(AllEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.All);
|
||||
|
||||
uriParseTreeVisitor.visitAllEOF(ctxResourcePathEOF);
|
||||
} else if (firstSegment.startsWith("$crossjoin")) {
|
||||
ensureLastSegment(firstSegment, 1, uri.pathSegmentListDecoded.size());
|
||||
CrossjoinEOFContext ctxResourcePathEOF =
|
||||
(CrossjoinEOFContext) parseRule(uri.pathSegmentListDecoded.get(0), ParserEntryRules.CrossJoin);
|
||||
context.contextUriInfo = new ResourcePathParser(edm, odata)
|
||||
.parseCrossjoinSegment(uri.pathSegmentListDecoded.get(0));
|
||||
final EdmEntityContainer container = edm.getEntityContainer();
|
||||
for (final String name : context.contextUriInfo.getEntitySetNames()) {
|
||||
context.contextTypes.push(
|
||||
uriParseTreeVisitor.new TypeInformation(container.getEntitySet(name).getEntityType(), true));
|
||||
}
|
||||
|
||||
uriParseTreeVisitor.visitCrossjoinEOF(ctxResourcePathEOF);
|
||||
} else {
|
||||
List<PathSegmentEOFContext> ctxPathSegments = new ArrayList<PathSegmentEOFContext>();
|
||||
for (String pathSegment : uri.pathSegmentListDecoded) {
|
||||
PathSegmentEOFContext ctxPathSegment =
|
||||
(PathSegmentEOFContext) parseRule(pathSegment, ParserEntryRules.PathSegment);
|
||||
ctxPathSegments.add(ctxPathSegment);
|
||||
}
|
||||
|
||||
context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
|
||||
|
||||
for (PathSegmentEOFContext ctxPathSegment : ctxPathSegments) {
|
||||
// add checks for batch, entity, metadata, all, crossjoin
|
||||
uriParseTreeVisitor.visitPathSegmentEOF(ctxPathSegment);
|
||||
final ResourcePathParser resourcePathParser = new ResourcePathParser(edm, odata);
|
||||
int count = 0;
|
||||
UriResource lastSegment = null;
|
||||
for (final String pathSegment : uri.pathSegmentListDecoded) {
|
||||
count++;
|
||||
final UriResource segment = resourcePathParser.parsePathSegment(pathSegment, lastSegment);
|
||||
if (segment != null) {
|
||||
if (segment instanceof UriResourceCount
|
||||
|| segment instanceof UriResourceRef
|
||||
|| segment instanceof UriResourceValue) {
|
||||
ensureLastSegment(pathSegment, count, uri.pathSegmentListDecoded.size());
|
||||
} else if (segment instanceof UriResourceAction
|
||||
|| segment instanceof UriResourceFunction
|
||||
&& !((UriResourceFunction) segment).getFunction().isComposable()) {
|
||||
if (count < uri.pathSegmentListDecoded.size()) {
|
||||
throw new UriValidationException(
|
||||
"The segment of an action or of a non-composable function must be the last resource-path segment.",
|
||||
UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
|
||||
uri.pathSegmentListDecoded.get(count));
|
||||
}
|
||||
lastSegment = segment;
|
||||
} else if (segment instanceof UriResourceStartingTypeFilterImpl) {
|
||||
throw new UriParserSemanticException("First resource-path segment must not be namespace-qualified.",
|
||||
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
|
||||
} else {
|
||||
lastSegment = segment;
|
||||
}
|
||||
context.contextUriInfo.addResourcePart(segment);
|
||||
}
|
||||
}
|
||||
|
||||
UriResource lastSegment = context.contextUriInfo.getLastResourcePart();
|
||||
if (lastSegment instanceof UriResourceCount
|
||||
|| lastSegment instanceof UriResourceRef
|
||||
|| lastSegment instanceof UriResourceValue) {
|
||||
final List<UriResource> parts = context.contextUriInfo.getUriResourceParts();
|
||||
lastSegment = parts.get(parts.size() - 2);
|
||||
}
|
||||
if (lastSegment instanceof UriResourcePartTyped) {
|
||||
UriResourcePartTyped typed = (UriResourcePartTyped) lastSegment;
|
||||
|
||||
@ -174,13 +186,12 @@ public class Parser {
|
||||
}
|
||||
|
||||
// second, read the system query options and the custom query options
|
||||
for (RawUri.QueryOption option : uri.queryOptionListDecoded) {
|
||||
for (final RawUri.QueryOption option : uri.queryOptionListDecoded) {
|
||||
if (option.name.startsWith("$")) {
|
||||
SystemQueryOption systemOption = null;
|
||||
if (option.name.equals(SystemQueryOptionKind.FILTER.toString())) {
|
||||
FilterExpressionEOFContext ctxFilterExpression =
|
||||
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
|
||||
|
||||
systemOption = (FilterOptionImpl) uriParseTreeVisitor.visitFilterExpressionEOF(ctxFilterExpression);
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.FORMAT.toString())) {
|
||||
@ -201,7 +212,6 @@ public class Parser {
|
||||
} else if (option.name.equals(SystemQueryOptionKind.EXPAND.toString())) {
|
||||
ExpandItemsEOFContext ctxExpandItems =
|
||||
(ExpandItemsEOFContext) parseRule(option.value, ParserEntryRules.ExpandItems);
|
||||
|
||||
systemOption = (ExpandOptionImpl) uriParseTreeVisitor.visitExpandItemsEOF(ctxExpandItems);
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.ID.toString())) {
|
||||
@ -210,22 +220,24 @@ public class Parser {
|
||||
idOption.setText(option.value);
|
||||
idOption.setValue(option.value);
|
||||
systemOption = idOption;
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.LEVELS.toString())) {
|
||||
throw new UriParserSyntaxException("System query option '$levels' is allowed only inside '$expand'!",
|
||||
UriParserSyntaxException.MessageKeys.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE);
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.ORDERBY.toString())) {
|
||||
OrderByEOFContext ctxOrderByExpression =
|
||||
(OrderByEOFContext) parseRule(option.value, ParserEntryRules.Orderby);
|
||||
|
||||
systemOption = (OrderByOptionImpl) uriParseTreeVisitor.visitOrderByEOF(ctxOrderByExpression);
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.SEARCH.toString())) {
|
||||
SearchParser searchParser = new SearchParser();
|
||||
systemOption = searchParser.parse(option.value);
|
||||
systemOption = new SearchParser().parse(option.value);
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.SELECT.toString())) {
|
||||
SelectEOFContext ctxSelectEOF =
|
||||
(SelectEOFContext) parseRule(option.value, ParserEntryRules.Select);
|
||||
|
||||
systemOption = (SelectOptionImpl) uriParseTreeVisitor.visitSelectEOF(ctxSelectEOF);
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.SKIP.toString())) {
|
||||
SkipOptionImpl skipOption = new SkipOptionImpl();
|
||||
skipOption.setName(option.name);
|
||||
@ -238,12 +250,14 @@ public class Parser {
|
||||
option.name, option.value);
|
||||
}
|
||||
systemOption = skipOption;
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.SKIPTOKEN.toString())) {
|
||||
SkipTokenOptionImpl skipTokenOption = new SkipTokenOptionImpl();
|
||||
skipTokenOption.setName(option.name);
|
||||
skipTokenOption.setText(option.value);
|
||||
skipTokenOption.setValue(option.value);
|
||||
systemOption = skipTokenOption;
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.TOP.toString())) {
|
||||
TopOptionImpl topOption = new TopOptionImpl();
|
||||
topOption.setName(option.name);
|
||||
@ -256,6 +270,7 @@ public class Parser {
|
||||
option.name, option.value);
|
||||
}
|
||||
systemOption = topOption;
|
||||
|
||||
} else if (option.name.equals(SystemQueryOptionKind.COUNT.toString())) {
|
||||
CountOptionImpl inlineCountOption = new CountOptionImpl();
|
||||
inlineCountOption.setName(option.name);
|
||||
@ -268,6 +283,7 @@ public class Parser {
|
||||
option.name, option.value);
|
||||
}
|
||||
systemOption = inlineCountOption;
|
||||
|
||||
} else {
|
||||
throw new UriParserSyntaxException("Unknown system query option!",
|
||||
UriParserSyntaxException.MessageKeys.UNKNOWN_SYSTEM_QUERY_OPTION, option.name);
|
||||
@ -278,12 +294,23 @@ public class Parser {
|
||||
throw new UriParserSyntaxException("Double system query option!", e,
|
||||
UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION, option.name);
|
||||
}
|
||||
|
||||
} else if (option.name.startsWith(AT)) {
|
||||
if (context.contextUriInfo.getAlias(option.name) == null) {
|
||||
final FilterExpressionEOFContext filterExpCtx =
|
||||
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
|
||||
final Expression expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
|
||||
.getExpression();
|
||||
// TODO: Create a proper alias-value parser that can parse also common expressions.
|
||||
Expression expression = null;
|
||||
if (!option.value.isEmpty() && (option.value.charAt(0) == '[' || option.value.charAt(0) == '{')) {
|
||||
UriTokenizer tokenizer = new UriTokenizer(option.value);
|
||||
if (!(tokenizer.next(TokenKind.jsonArrayOrObject) && tokenizer.next(TokenKind.EOF))) {
|
||||
throw new UriParserSyntaxException("Illegal value for alias '" + option.name + "'.",
|
||||
UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
} else {
|
||||
final FilterExpressionEOFContext filterExpCtx =
|
||||
(FilterExpressionEOFContext) parseRule(option.value, ParserEntryRules.FilterExpression);
|
||||
expression = ((FilterOption) uriParseTreeVisitor.visitFilterExpressionEOF(filterExpCtx))
|
||||
.getExpression();
|
||||
}
|
||||
context.contextUriInfo.addAlias((AliasQueryOption) new AliasQueryOptionImpl()
|
||||
.setAliasValue(expression)
|
||||
.setName(option.name)
|
||||
@ -292,6 +319,7 @@ public class Parser {
|
||||
throw new UriParserSyntaxException("Alias already specified! Name: " + option.name,
|
||||
UriParserSyntaxException.MessageKeys.DUPLICATED_ALIAS, option.name);
|
||||
}
|
||||
|
||||
} else {
|
||||
context.contextUriInfo.addCustomQueryOption((CustomQueryOption)
|
||||
new CustomQueryOptionImpl()
|
||||
@ -354,21 +382,6 @@ public class Parser {
|
||||
|
||||
// parse
|
||||
switch (entryPoint) {
|
||||
case All:
|
||||
ret = parser.allEOF();
|
||||
break;
|
||||
case Batch:
|
||||
ret = parser.batchEOF();
|
||||
break;
|
||||
case CrossJoin:
|
||||
ret = parser.crossjoinEOF();
|
||||
break;
|
||||
case Metadata:
|
||||
ret = parser.metadataEOF();
|
||||
break;
|
||||
case PathSegment:
|
||||
ret = parser.pathSegmentEOF();
|
||||
break;
|
||||
case FilterExpression:
|
||||
lexer.mode(Lexer.DEFAULT_MODE);
|
||||
ret = parser.filterExpressionEOF();
|
||||
@ -381,15 +394,9 @@ public class Parser {
|
||||
lexer.mode(Lexer.DEFAULT_MODE);
|
||||
ret = parser.expandItemsEOF();
|
||||
break;
|
||||
case Entity:
|
||||
ret = parser.entityEOF();
|
||||
break;
|
||||
case Select:
|
||||
ret = parser.selectEOF();
|
||||
break;
|
||||
case Search:
|
||||
ret = parser.searchInline();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -414,21 +421,6 @@ public class Parser {
|
||||
|
||||
// parse
|
||||
switch (entryPoint) {
|
||||
case All:
|
||||
ret = parser.allEOF();
|
||||
break;
|
||||
case Batch:
|
||||
ret = parser.batchEOF();
|
||||
break;
|
||||
case CrossJoin:
|
||||
ret = parser.crossjoinEOF();
|
||||
break;
|
||||
case Metadata:
|
||||
ret = parser.metadataEOF();
|
||||
break;
|
||||
case PathSegment:
|
||||
ret = parser.pathSegmentEOF();
|
||||
break;
|
||||
case FilterExpression:
|
||||
lexer.mode(Lexer.DEFAULT_MODE);
|
||||
ret = parser.filterExpressionEOF();
|
||||
@ -441,15 +433,9 @@ public class Parser {
|
||||
lexer.mode(Lexer.DEFAULT_MODE);
|
||||
ret = parser.expandItemsEOF();
|
||||
break;
|
||||
case Entity:
|
||||
ret = parser.entityEOF();
|
||||
break;
|
||||
case Select:
|
||||
ret = parser.selectEOF();
|
||||
break;
|
||||
case Search:
|
||||
ret = parser.searchInline();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -0,0 +1,692 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmAction;
|
||||
import org.apache.olingo.commons.api.edm.EdmActionImport;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunction;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
|
||||
import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmSingleton;
|
||||
import org.apache.olingo.commons.api.edm.EdmStructuredType;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
|
||||
import org.apache.olingo.server.core.uri.UriInfoImpl;
|
||||
import org.apache.olingo.server.core.uri.UriParameterImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceActionImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceComplexPropertyImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceCountImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceEntitySetImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceFunctionImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceNavigationPropertyImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourcePrimitivePropertyImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceRefImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceSingletonImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceTypedImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceValueImpl;
|
||||
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
|
||||
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
|
||||
public class ResourcePathParser {
|
||||
|
||||
private final Edm edm;
|
||||
private final EdmEntityContainer edmEntityContainer;
|
||||
private final OData odata;
|
||||
private UriTokenizer tokenizer;
|
||||
|
||||
public ResourcePathParser(final Edm edm, final OData odata) {
|
||||
this.edm = edm;
|
||||
edmEntityContainer = edm.getEntityContainer();
|
||||
this.odata = odata;
|
||||
}
|
||||
|
||||
public UriResource parsePathSegment(final String pathSegment, UriResource previous)
|
||||
throws UriParserException, UriValidationException {
|
||||
tokenizer = new UriTokenizer(pathSegment);
|
||||
|
||||
// The order is important.
|
||||
// A qualified name should not be parsed as identifier and let the tokenizer halt at '.'.
|
||||
|
||||
if (previous == null) {
|
||||
if (tokenizer.next(TokenKind.QualifiedName)) {
|
||||
throw new UriParserSemanticException("The initial segment must not be namespace-qualified.",
|
||||
UriParserSemanticException.MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT,
|
||||
new FullQualifiedName(tokenizer.getText()).getNamespace());
|
||||
} else if (tokenizer.next(TokenKind.ODataIdentifier)) {
|
||||
return leadingResourcePathSegment();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (tokenizer.next(TokenKind.REF)) {
|
||||
return ref(previous);
|
||||
} else if (tokenizer.next(TokenKind.VALUE)) {
|
||||
return value(previous);
|
||||
} else if (tokenizer.next(TokenKind.COUNT)) {
|
||||
return count(previous);
|
||||
} else if (tokenizer.next(TokenKind.QualifiedName)) {
|
||||
return boundOperationOrTypeCast(previous);
|
||||
} else if (tokenizer.next(TokenKind.ODataIdentifier)) {
|
||||
return navigationOrProperty(previous);
|
||||
}
|
||||
}
|
||||
|
||||
throw new UriParserSyntaxException("Unexpected start of resource-path segment.",
|
||||
UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
|
||||
public UriInfoImpl parseDollarEntityTypeCast(final String pathSegment) throws UriParserException {
|
||||
UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.entityId);
|
||||
tokenizer = new UriTokenizer(pathSegment);
|
||||
requireNext(TokenKind.QualifiedName);
|
||||
final String name = tokenizer.getText();
|
||||
requireTokenEnd();
|
||||
final EdmEntityType type = edm.getEntityType(new FullQualifiedName(name));
|
||||
if (type == null) {
|
||||
throw new UriParserSemanticException("Type '" + name + "' not found.",
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, name);
|
||||
} else {
|
||||
uriInfo.setEntityTypeCast(type);
|
||||
}
|
||||
return uriInfo;
|
||||
}
|
||||
|
||||
public UriInfoImpl parseCrossjoinSegment(final String pathSegment) throws UriParserException {
|
||||
UriInfoImpl uriInfo = new UriInfoImpl().setKind(UriInfoKind.crossjoin);
|
||||
tokenizer = new UriTokenizer(pathSegment);
|
||||
requireNext(TokenKind.CROSSJOIN);
|
||||
requireNext(TokenKind.OPEN);
|
||||
// At least one entity-set name is mandatory. Try to fetch all.
|
||||
do {
|
||||
requireNext(TokenKind.ODataIdentifier);
|
||||
final String name = tokenizer.getText();
|
||||
final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(name);
|
||||
if (edmEntitySet == null) {
|
||||
throw new UriParserSemanticException("Expected Entity Set Name.",
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_PART, name);
|
||||
} else {
|
||||
uriInfo.addEntitySetName(name);
|
||||
}
|
||||
} while (tokenizer.next(TokenKind.COMMA));
|
||||
requireNext(TokenKind.CLOSE);
|
||||
requireTokenEnd();
|
||||
return uriInfo;
|
||||
}
|
||||
|
||||
private UriResource ref(final UriResource previous) throws UriParserException {
|
||||
requireTokenEnd();
|
||||
requireTyped(previous, "$ref");
|
||||
if (((UriResourcePartTyped) previous).getType() instanceof EdmEntityType) {
|
||||
return new UriResourceRefImpl();
|
||||
} else {
|
||||
throw new UriParserSemanticException("$ref is only allowed on entity types.",
|
||||
UriParserSemanticException.MessageKeys.ONLY_FOR_ENTITY_TYPES, "$ref");
|
||||
}
|
||||
}
|
||||
|
||||
private UriResource value(final UriResource previous) throws UriParserException {
|
||||
requireTokenEnd();
|
||||
requireTyped(previous, "$value");
|
||||
if (!((UriResourcePartTyped) previous).isCollection()) {
|
||||
return new UriResourceValueImpl();
|
||||
} else {
|
||||
throw new UriParserSemanticException("$value is only allowed on typed path segments.",
|
||||
UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS, "$value");
|
||||
}
|
||||
}
|
||||
|
||||
private UriResource count(final UriResource previous) throws UriParserException {
|
||||
requireTokenEnd();
|
||||
requireTyped(previous, "$count");
|
||||
if (((UriResourcePartTyped) previous).isCollection()) {
|
||||
return new UriResourceCountImpl();
|
||||
} else {
|
||||
throw new UriParserSemanticException("$count is only allowed on collections.",
|
||||
UriParserSemanticException.MessageKeys.ONLY_FOR_COLLECTIONS, "$count");
|
||||
}
|
||||
}
|
||||
|
||||
private UriResource leadingResourcePathSegment() throws UriParserException, UriValidationException {
|
||||
final String oDataIdentifier = tokenizer.getText();
|
||||
|
||||
final EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(oDataIdentifier);
|
||||
if (edmEntitySet != null) {
|
||||
final UriResourceEntitySetImpl entitySetResource = new UriResourceEntitySetImpl().setEntitSet(edmEntitySet);
|
||||
|
||||
if (tokenizer.next(TokenKind.OPEN)) {
|
||||
final List<UriParameter> keyPredicates = keyPredicate(entitySetResource.getEntityType(), null);
|
||||
entitySetResource.setKeyPredicates(keyPredicates);
|
||||
}
|
||||
|
||||
requireTokenEnd();
|
||||
return entitySetResource;
|
||||
}
|
||||
|
||||
final EdmSingleton edmSingleton = edmEntityContainer.getSingleton(oDataIdentifier);
|
||||
if (edmSingleton != null) {
|
||||
requireTokenEnd();
|
||||
return new UriResourceSingletonImpl().setSingleton(edmSingleton);
|
||||
}
|
||||
|
||||
final EdmActionImport edmActionImport = edmEntityContainer.getActionImport(oDataIdentifier);
|
||||
if (edmActionImport != null) {
|
||||
requireTokenEnd();
|
||||
return new UriResourceActionImpl().setActionImport(edmActionImport);
|
||||
}
|
||||
|
||||
final EdmFunctionImport edmFunctionImport = edmEntityContainer.getFunctionImport(oDataIdentifier);
|
||||
if (edmFunctionImport != null) {
|
||||
return functionCall(edmFunctionImport, null, null, false);
|
||||
}
|
||||
|
||||
if (tokenizer.next(TokenKind.OPEN) || tokenizer.next(TokenKind.EOF)) {
|
||||
throw new UriParserSemanticException("Unexpected start of resource-path segment.",
|
||||
UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND, oDataIdentifier);
|
||||
} else {
|
||||
throw new UriParserSyntaxException("Unexpected start of resource-path segment.",
|
||||
UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
private UriResource navigationOrProperty(final UriResource previous)
|
||||
throws UriParserException, UriValidationException {
|
||||
final String name = tokenizer.getText();
|
||||
|
||||
UriResourcePartTyped previousTyped = null;
|
||||
EdmStructuredType structType = null;
|
||||
requireTyped(previous, name);
|
||||
if (((UriResourcePartTyped) previous).getType() instanceof EdmStructuredType) {
|
||||
previousTyped = (UriResourcePartTyped) previous;
|
||||
final EdmType previousTypeFilter = getPreviousTypeFilter(previousTyped);
|
||||
structType = (EdmStructuredType) (previousTypeFilter == null ? previousTyped.getType() : previousTypeFilter);
|
||||
} else {
|
||||
throw new UriParserSemanticException(
|
||||
"Cannot parse '" + name + "'; previous path segment is not a structural type.",
|
||||
UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE, name);
|
||||
}
|
||||
|
||||
if (previousTyped.isCollection()) {
|
||||
throw new UriParserSemanticException("Property '" + name + "' is not allowed after collection.",
|
||||
UriParserSemanticException.MessageKeys.PROPERTY_AFTER_COLLECTION, name);
|
||||
}
|
||||
|
||||
final EdmProperty property = structType.getStructuralProperty(name);
|
||||
if (property != null) {
|
||||
return property.isPrimitive()
|
||||
|| property.getType().getKind() == EdmTypeKind.ENUM
|
||||
|| property.getType().getKind() == EdmTypeKind.DEFINITION ?
|
||||
new UriResourcePrimitivePropertyImpl().setProperty(property) :
|
||||
new UriResourceComplexPropertyImpl().setProperty(property);
|
||||
}
|
||||
final EdmNavigationProperty navigationProperty = structType.getNavigationProperty(name);
|
||||
if (navigationProperty == null) {
|
||||
throw new UriParserSemanticException("Property '" + name + "' not found in type '"
|
||||
+ structType.getFullQualifiedName().getFullQualifiedNameAsString() + "'",
|
||||
UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE,
|
||||
structType.getFullQualifiedName().getFullQualifiedNameAsString(), name);
|
||||
}
|
||||
List<UriParameter> keyPredicate = null;
|
||||
if (tokenizer.next(TokenKind.OPEN)) {
|
||||
if (navigationProperty.isCollection()) {
|
||||
keyPredicate = keyPredicate(navigationProperty.getType(), navigationProperty.getPartner());
|
||||
} else {
|
||||
throw new UriParserSemanticException("A key is not allowed on non-collection navigation properties.",
|
||||
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
requireTokenEnd();
|
||||
return new UriResourceNavigationPropertyImpl()
|
||||
.setNavigationProperty(navigationProperty)
|
||||
.setKeyPredicates(keyPredicate);
|
||||
}
|
||||
|
||||
private UriResource boundOperationOrTypeCast(UriResource previous)
|
||||
throws UriParserException, UriValidationException {
|
||||
final FullQualifiedName name = new FullQualifiedName(tokenizer.getText());
|
||||
requireTyped(previous, name.getFullQualifiedNameAsString());
|
||||
final UriResourcePartTyped previousTyped = (UriResourcePartTyped) previous;
|
||||
final EdmType previousTypeFilter = getPreviousTypeFilter(previousTyped);
|
||||
final EdmType previousType = previousTypeFilter == null ? previousTyped.getType() : previousTypeFilter;
|
||||
final EdmAction boundAction = edm.getBoundAction(name,
|
||||
previousType.getFullQualifiedName(),
|
||||
previousTyped.isCollection());
|
||||
if (boundAction != null) {
|
||||
requireTokenEnd();
|
||||
return new UriResourceActionImpl().setAction(boundAction);
|
||||
}
|
||||
EdmStructuredType type = edm.getEntityType(name);
|
||||
if (type == null) {
|
||||
type = edm.getComplexType(name);
|
||||
}
|
||||
if (type != null) {
|
||||
return typeCast(name, type, previousTyped);
|
||||
}
|
||||
if (tokenizer.next(TokenKind.EOF)) {
|
||||
throw new UriParserSemanticException("Type '" + name.getFullQualifiedNameAsString() + "' not found.",
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_TYPE, name.getFullQualifiedNameAsString());
|
||||
}
|
||||
return functionCall(null, name,
|
||||
previousType.getFullQualifiedName(),
|
||||
previousTyped.isCollection());
|
||||
}
|
||||
|
||||
private void requireTyped(final UriResource previous, final String forWhat) throws UriParserException {
|
||||
if (previous == null || !(previous instanceof UriResourcePartTyped)) {
|
||||
throw new UriParserSemanticException("Path segment before '" + forWhat + "' is not typed.",
|
||||
UriParserSemanticException.MessageKeys.PREVIOUS_PART_NOT_TYPED, forWhat);
|
||||
}
|
||||
}
|
||||
|
||||
private List<UriParameter> keyPredicate(final EdmEntityType edmEntityType, final EdmNavigationProperty partner)
|
||||
throws UriParserException, UriValidationException {
|
||||
final List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
|
||||
if (tokenizer.next(TokenKind.CLOSE)) {
|
||||
throw new UriParserSemanticException(
|
||||
"Expected " + keyPropertyRefs.size() + " key predicates but none.",
|
||||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
|
||||
Integer.toString(keyPropertyRefs.size()), "0");
|
||||
}
|
||||
List<UriParameter> keys = new ArrayList<UriParameter>();
|
||||
Map<String, String> referencedNames = new HashMap<String, String>();
|
||||
|
||||
if (partner != null) {
|
||||
// Prepare list of potentially missing keys to be filled from referential constraints.
|
||||
for (final String name : edmEntityType.getKeyPredicateNames()) {
|
||||
final String referencedName = partner.getReferencingPropertyName(name);
|
||||
if (referencedName != null) {
|
||||
referencedNames.put(name, referencedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tokenizer.next(TokenKind.ODataIdentifier)) {
|
||||
keys.addAll(compoundKey(edmEntityType));
|
||||
} else if (keyPropertyRefs.size() - referencedNames.size() == 1) {
|
||||
for (final EdmKeyPropertyRef candidate : keyPropertyRefs) {
|
||||
if (referencedNames.get(candidate.getName()) == null) {
|
||||
keys.add(simpleKey(candidate));
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new UriParserSemanticException(
|
||||
"Expected " + (keyPropertyRefs.size() -referencedNames.size()) + " key predicates but found one.",
|
||||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
|
||||
Integer.toString(keyPropertyRefs.size() - referencedNames.size()), "1");
|
||||
}
|
||||
|
||||
if (keys.size() < keyPropertyRefs.size() && partner != null) {
|
||||
// Fill missing keys from referential constraints.
|
||||
for (final String name : edmEntityType.getKeyPredicateNames()) {
|
||||
boolean found = false;
|
||||
for (final UriParameter key : keys) {
|
||||
if (name.equals(key.getName())) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found && referencedNames.get(name) != null) {
|
||||
keys.add(0, new UriParameterImpl().setName(name).setReferencedProperty(referencedNames.get(name)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that all key predicates are filled from the URI.
|
||||
if (keys.size() < keyPropertyRefs.size()) {
|
||||
throw new UriParserSemanticException(
|
||||
"Expected " + keyPropertyRefs.size() + " key predicates but found " + keys.size() + ".",
|
||||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
|
||||
Integer.toString(keyPropertyRefs.size()), Integer.toString(keys.size()));
|
||||
} else {
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
|
||||
private UriParameter simpleKey(final EdmKeyPropertyRef edmKeyPropertyRef)
|
||||
throws UriParserException, UriValidationException {
|
||||
final EdmProperty edmProperty = edmKeyPropertyRef == null ? null : edmKeyPropertyRef.getProperty();
|
||||
if (nextPrimitiveTypeValue(
|
||||
edmProperty == null ? null : (EdmPrimitiveType) edmProperty.getType(),
|
||||
edmProperty == null ? false : edmProperty.isNullable())) {
|
||||
final String literalValue = tokenizer.getText();
|
||||
requireNext(TokenKind.CLOSE);
|
||||
return createUriParameter(edmProperty, edmKeyPropertyRef.getName(), literalValue);
|
||||
} else {
|
||||
throw new UriParserSemanticException("The key value is not valid.",
|
||||
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, edmKeyPropertyRef.getName());
|
||||
}
|
||||
}
|
||||
|
||||
private List<UriParameter> compoundKey(final EdmEntityType edmEntityType)
|
||||
throws UriParserException, UriValidationException {
|
||||
|
||||
List<UriParameter> parameters = new ArrayList<UriParameter>();
|
||||
List<String> parameterNames = new ArrayList<String>();
|
||||
|
||||
// To validate that each key predicate is exactly specified once, we use a list to pick from.
|
||||
List<String> remainingKeyNames = new ArrayList<String>(edmEntityType.getKeyPredicateNames());
|
||||
|
||||
// At least one key predicate is mandatory. Try to fetch all.
|
||||
boolean hasComma = false;
|
||||
do {
|
||||
final String keyPredicateName = tokenizer.getText();
|
||||
if (parameterNames.contains(keyPredicateName)) {
|
||||
throw new UriValidationException("Duplicated key property " + keyPredicateName,
|
||||
UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY, keyPredicateName);
|
||||
}
|
||||
if (remainingKeyNames.isEmpty()) {
|
||||
throw new UriParserSemanticException("Too many key properties.",
|
||||
UriParserSemanticException.MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES,
|
||||
Integer.toString(parameters.size()), Integer.toString(parameters.size() + 1));
|
||||
}
|
||||
if (!remainingKeyNames.remove(keyPredicateName)) {
|
||||
throw new UriValidationException("Unknown key property " + keyPredicateName,
|
||||
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
|
||||
}
|
||||
parameters.add(keyValuePair(keyPredicateName, edmEntityType));
|
||||
parameterNames.add(keyPredicateName);
|
||||
hasComma = tokenizer.next(TokenKind.COMMA);
|
||||
if (hasComma) {
|
||||
requireNext(TokenKind.ODataIdentifier);
|
||||
}
|
||||
} while (hasComma);
|
||||
requireNext(TokenKind.CLOSE);
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private UriParameter keyValuePair(final String keyPredicateName, final EdmEntityType edmEntityType)
|
||||
throws UriParserException, UriValidationException {
|
||||
final EdmKeyPropertyRef keyPropertyRef = edmEntityType.getKeyPropertyRef(keyPredicateName);
|
||||
final EdmProperty edmProperty = keyPropertyRef == null ? null : keyPropertyRef.getProperty();
|
||||
if (edmProperty == null) {
|
||||
throw new UriValidationException(keyPredicateName + " is not a valid key property name.",
|
||||
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, keyPredicateName);
|
||||
}
|
||||
requireNext(TokenKind.EQ);
|
||||
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
|
||||
throw new UriParserSyntaxException("Key value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
if (nextPrimitiveTypeValue((EdmPrimitiveType) edmProperty.getType(), edmProperty.isNullable())) {
|
||||
return createUriParameter(edmProperty, keyPredicateName, tokenizer.getText());
|
||||
} else {
|
||||
throw new UriParserSemanticException(keyPredicateName + " has not a valid key value.",
|
||||
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, keyPredicateName);
|
||||
}
|
||||
}
|
||||
|
||||
private UriParameter createUriParameter(final EdmProperty edmProperty, final String parameterName,
|
||||
final String literalValue) throws UriParserException, UriValidationException {
|
||||
if (literalValue.startsWith("@")) {
|
||||
return new UriParameterImpl()
|
||||
.setName(parameterName)
|
||||
.setAlias(literalValue);
|
||||
}
|
||||
|
||||
final EdmPrimitiveType primitiveType = (EdmPrimitiveType) edmProperty.getType();
|
||||
try {
|
||||
if (!(primitiveType.validate(primitiveType.fromUriLiteral(literalValue), edmProperty.isNullable(),
|
||||
edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode()))) {
|
||||
throw new UriValidationException("Invalid key property",
|
||||
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
|
||||
}
|
||||
} catch (final EdmPrimitiveTypeException e) {
|
||||
throw new UriValidationException("Invalid key property",
|
||||
UriValidationException.MessageKeys.INVALID_KEY_PROPERTY, parameterName);
|
||||
}
|
||||
|
||||
return new UriParameterImpl()
|
||||
.setName(parameterName)
|
||||
.setText("null".equals(literalValue) ? null : literalValue);
|
||||
}
|
||||
|
||||
private UriResource typeCast(final FullQualifiedName name, final EdmStructuredType type,
|
||||
final UriResourcePartTyped previousTyped) throws UriParserException, UriValidationException {
|
||||
if (type.compatibleTo(previousTyped.getType())) {
|
||||
EdmType previousTypeFilter = null;
|
||||
if (previousTyped instanceof UriResourceWithKeysImpl) {
|
||||
if (previousTyped.isCollection()) {
|
||||
previousTypeFilter = ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnCollection();
|
||||
if (previousTypeFilter != null) {
|
||||
throw new UriParserSemanticException("Type filters are not chainable.",
|
||||
UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
|
||||
previousTypeFilter.getName(), type.getName());
|
||||
}
|
||||
((UriResourceWithKeysImpl) previousTyped).setCollectionTypeFilter(type);
|
||||
} else {
|
||||
previousTypeFilter = ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnEntry();
|
||||
if (previousTypeFilter != null) {
|
||||
throw new UriParserSemanticException("Type filters are not chainable.",
|
||||
UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
|
||||
previousTypeFilter.getName(), type.getName());
|
||||
}
|
||||
((UriResourceWithKeysImpl) previousTyped).setEntryTypeFilter(type);
|
||||
}
|
||||
if (tokenizer.next(TokenKind.OPEN)) {
|
||||
((UriResourceWithKeysImpl) previousTyped).setKeyPredicates(
|
||||
keyPredicate((EdmEntityType) type, null));
|
||||
}
|
||||
} else {
|
||||
previousTypeFilter = ((UriResourceTypedImpl) previousTyped).getTypeFilter();
|
||||
if (previousTypeFilter != null) {
|
||||
throw new UriParserSemanticException("Type filters are not chainable.",
|
||||
UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE,
|
||||
previousTypeFilter.getName(), type.getName());
|
||||
}
|
||||
((UriResourceTypedImpl) previousTyped).setTypeFilter(type);
|
||||
}
|
||||
requireTokenEnd();
|
||||
return null;
|
||||
} else {
|
||||
throw new UriParserSemanticException(
|
||||
"Type filter not compatible to previous path segment: " + name.getFullQualifiedNameAsString(),
|
||||
UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, name.getFullQualifiedNameAsString());
|
||||
}
|
||||
}
|
||||
|
||||
private EdmType getPreviousTypeFilter(final UriResourcePartTyped previousTyped) {
|
||||
if (previousTyped instanceof UriResourceWithKeysImpl) {
|
||||
return ((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnEntry() == null ?
|
||||
((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnCollection() :
|
||||
((UriResourceWithKeysImpl) previousTyped).getTypeFilterOnEntry();
|
||||
} else {
|
||||
return ((UriResourceTypedImpl) previousTyped).getTypeFilter();
|
||||
}
|
||||
}
|
||||
|
||||
private UriResource functionCall(final EdmFunctionImport edmFunctionImport,
|
||||
final FullQualifiedName boundFunctionName, final FullQualifiedName bindingParameterTypeName,
|
||||
final boolean isBindingParameterCollection) throws UriParserException, UriValidationException {
|
||||
final List<UriParameter> parameters = functionParameters();
|
||||
List<String> names = new ArrayList<String>();
|
||||
for (final UriParameter parameter : parameters) {
|
||||
names.add(parameter.getName());
|
||||
}
|
||||
EdmFunction function = null;
|
||||
if (edmFunctionImport != null) {
|
||||
function = edmFunctionImport.getUnboundFunction(names);
|
||||
if (function == null) {
|
||||
throw new UriParserSemanticException(
|
||||
"Function of function import '" + edmFunctionImport.getName() + "' "
|
||||
+ "with parameters " + names.toString() + " not found.",
|
||||
UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND, edmFunctionImport.getName(), names.toString());
|
||||
}
|
||||
} else {
|
||||
function = edm.getBoundFunction(boundFunctionName,
|
||||
bindingParameterTypeName, isBindingParameterCollection, names);
|
||||
if (function == null) {
|
||||
throw new UriParserSemanticException(
|
||||
"Function " + boundFunctionName + " not found.",
|
||||
UriParserSemanticException.MessageKeys.UNKNOWN_PART, boundFunctionName.getFullQualifiedNameAsString());
|
||||
}
|
||||
}
|
||||
UriResourceFunctionImpl resource = new UriResourceFunctionImpl()
|
||||
.setFunctionImport(edmFunctionImport, null)
|
||||
.setFunction(function)
|
||||
.setParameters(parameters);
|
||||
if (tokenizer.next(TokenKind.OPEN)) {
|
||||
if (function.getReturnType() != null
|
||||
&& function.getReturnType().getType().getKind() == EdmTypeKind.ENTITY
|
||||
&& function.getReturnType().isCollection()) {
|
||||
resource.setKeyPredicates(
|
||||
keyPredicate((EdmEntityType) function.getReturnType().getType(), null));
|
||||
} else {
|
||||
throw new UriParserSemanticException("A key is not allowed.",
|
||||
UriParserSemanticException.MessageKeys.KEY_NOT_ALLOWED);
|
||||
}
|
||||
}
|
||||
requireTokenEnd();
|
||||
return resource;
|
||||
}
|
||||
|
||||
private List<UriParameter> functionParameters() throws UriParserException {
|
||||
List<UriParameter> parameters = new ArrayList<UriParameter>();
|
||||
requireNext(TokenKind.OPEN);
|
||||
if (tokenizer.next(TokenKind.CLOSE)) {
|
||||
return parameters;
|
||||
}
|
||||
do {
|
||||
requireNext(TokenKind.ODataIdentifier);
|
||||
final String name = tokenizer.getText();
|
||||
if (parameters.contains(name)) {
|
||||
throw new UriParserSemanticException("Duplicated function parameter " + name,
|
||||
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, name);
|
||||
}
|
||||
requireNext(TokenKind.EQ);
|
||||
if (tokenizer.next(TokenKind.COMMA) || tokenizer.next(TokenKind.CLOSE) || tokenizer.next(TokenKind.EOF)) {
|
||||
throw new UriParserSyntaxException("Parameter value expected.", UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
if (nextPrimitiveValue()) {
|
||||
final String literalValue = tokenizer.getText();
|
||||
UriParameterImpl parameter = new UriParameterImpl().setName(name);
|
||||
parameters.add(literalValue.startsWith("@") ?
|
||||
parameter.setAlias(literalValue) :
|
||||
parameter.setText("null".equals(literalValue) ? null : literalValue));
|
||||
} else {
|
||||
throw new UriParserSemanticException("Wrong parameter value.",
|
||||
UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE, "");
|
||||
}
|
||||
} while (tokenizer.next(TokenKind.COMMA));
|
||||
requireNext(TokenKind.CLOSE);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
private void requireNext(final TokenKind kind) throws UriParserException {
|
||||
if (!tokenizer.next(kind)) {
|
||||
throw new UriParserSyntaxException("Expected token '" + kind.toString() + "' not found.",
|
||||
UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
}
|
||||
|
||||
private void requireTokenEnd() throws UriParserException {
|
||||
requireNext(TokenKind.EOF);
|
||||
}
|
||||
|
||||
private boolean nextPrimitiveTypeValue(final EdmPrimitiveType primitiveType, final boolean nullable) {
|
||||
final EdmPrimitiveType type = primitiveType instanceof EdmTypeDefinition ?
|
||||
((EdmTypeDefinition) primitiveType).getUnderlyingType() :
|
||||
primitiveType;
|
||||
if (tokenizer.next(TokenKind.ParameterAliasName)) {
|
||||
return true;
|
||||
} else if (nullable && tokenizer.next(TokenKind.NULL)) {
|
||||
return true;
|
||||
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Boolean).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveBooleanValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.String).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveStringValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.SByte).equals(type)
|
||||
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Byte).equals(type)
|
||||
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int16).equals(type)
|
||||
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int32).equals(type)
|
||||
|| odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Int64).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveIntegerValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Guid).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveGuidValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Date).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveDateValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.DateTimeOffset).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.TimeOfDay).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveTimeOfDayValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Decimal).equals(type)) {
|
||||
// The order is important.
|
||||
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
|
||||
return tokenizer.next(TokenKind.PrimitiveDecimalValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveIntegerValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Double).equals(type)) {
|
||||
// The order is important.
|
||||
// A floating-point value should not be parsed as decimal and let the tokenizer stop at 'E'.
|
||||
// A decimal value should not be parsed as integer and let the tokenizer stop at the decimal point.
|
||||
return tokenizer.next(TokenKind.PrimitiveDoubleValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveDecimalValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveIntegerValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Duration).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveDurationValue);
|
||||
} else if (odata.createPrimitiveTypeInstance(EdmPrimitiveTypeKind.Binary).equals(type)) {
|
||||
return tokenizer.next(TokenKind.PrimitiveBinaryValue);
|
||||
} else if (type.getKind() == EdmTypeKind.ENUM) {
|
||||
return tokenizer.next(TokenKind.PrimitiveEnumValue);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nextPrimitiveValue() {
|
||||
return tokenizer.next(TokenKind.ParameterAliasName)
|
||||
|| tokenizer.next(TokenKind.NULL)
|
||||
|| tokenizer.next(TokenKind.PrimitiveBooleanValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveStringValue)
|
||||
|
||||
// The order of the next seven expressions is important in order to avoid
|
||||
// finding partly parsed tokens (counter-intuitive as it may be, even a GUID may start with digits ...).
|
||||
|| tokenizer.next(TokenKind.PrimitiveDoubleValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveDecimalValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveGuidValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveDateTimeOffsetValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveDateValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveTimeOfDayValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveIntegerValue)
|
||||
|
||||
|| tokenizer.next(TokenKind.PrimitiveDurationValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveBinaryValue)
|
||||
|| tokenizer.next(TokenKind.PrimitiveEnumValue);
|
||||
}
|
||||
}
|
@ -250,7 +250,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
|
||||
public UriParseTreeVisitor(final Edm edm, final UriContext context) {
|
||||
this.edm = edm;
|
||||
this.context = context;
|
||||
edmEntityContainer = edm.getEntityContainer(null);
|
||||
edmEntityContainer = edm.getEntityContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,592 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* <p>Simple OData URI tokenizer that works on a given string by keeping an index.</p>
|
||||
* <p>As far as feasible, it tries to work on character basis, assuming this to be faster than string operations.
|
||||
* Since only the index is "moved", backing out while parsing a token is easy and used throughout.
|
||||
* There is intentionally no method to push back tokens (although it would be easy to add such a method)
|
||||
* because this tokenizer should behave like a classical token-consuming tokenizer.</p>
|
||||
*/
|
||||
public class UriTokenizer {
|
||||
|
||||
public enum TokenKind {
|
||||
EOF, // signals the end of the string to be parsed
|
||||
|
||||
// constant-value tokens (convention: uppercase)
|
||||
REF,
|
||||
VALUE,
|
||||
COUNT,
|
||||
CROSSJOIN,
|
||||
OPEN,
|
||||
CLOSE,
|
||||
COMMA,
|
||||
SEMI,
|
||||
EQ,
|
||||
NULL,
|
||||
|
||||
// variable-value tokens (convention: mixed case)
|
||||
ODataIdentifier,
|
||||
QualifiedName,
|
||||
ParameterAliasName,
|
||||
|
||||
PrimitiveBooleanValue,
|
||||
PrimitiveStringValue,
|
||||
PrimitiveIntegerValue,
|
||||
PrimitiveGuidValue,
|
||||
PrimitiveDateValue,
|
||||
PrimitiveDateTimeOffsetValue,
|
||||
PrimitiveTimeOfDayValue,
|
||||
PrimitiveDecimalValue,
|
||||
PrimitiveDoubleValue,
|
||||
PrimitiveDurationValue,
|
||||
PrimitiveBinaryValue,
|
||||
PrimitiveEnumValue,
|
||||
|
||||
jsonArrayOrObject
|
||||
}
|
||||
|
||||
private final String pathSegment;
|
||||
|
||||
private int startIndex = 0;
|
||||
private int index = 0;
|
||||
|
||||
public UriTokenizer(final String pathSegment) {
|
||||
this.pathSegment = pathSegment == null ? "" : pathSegment;
|
||||
}
|
||||
|
||||
/** Returns the string value corresponding to the last successful {@link #next(TokenKind)} call. */
|
||||
public String getText() {
|
||||
return pathSegment.substring(startIndex, index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to find a token of the given token kind at the current index.
|
||||
* The order in which this method is called with different token kinds is important,
|
||||
* not only for performance reasons but also if tokens can start with the same characters
|
||||
* (e.g., a qualified name starts with an OData identifier).
|
||||
* @param allowedTokenKind the kind of token to expect
|
||||
* @return <code>true</code> if the token is found; <code>false</code> otherwise
|
||||
* @see #getText()
|
||||
*/
|
||||
public boolean next(final TokenKind allowedTokenKind) {
|
||||
if (allowedTokenKind == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean found = false;
|
||||
final int previousIndex = index;
|
||||
switch (allowedTokenKind) {
|
||||
// Constants
|
||||
case REF:
|
||||
found = nextConstant("$ref");
|
||||
break;
|
||||
case VALUE:
|
||||
found = nextConstant("$value");
|
||||
break;
|
||||
case COUNT:
|
||||
found = nextConstant("$count");
|
||||
break;
|
||||
case CROSSJOIN:
|
||||
found = nextConstant("$crossjoin");
|
||||
break;
|
||||
case OPEN:
|
||||
found = nextCharacter('(');
|
||||
break;
|
||||
case CLOSE:
|
||||
found = nextCharacter(')');
|
||||
break;
|
||||
case COMMA:
|
||||
found = nextCharacter(',');
|
||||
break;
|
||||
case SEMI:
|
||||
found = nextCharacter(';');
|
||||
break;
|
||||
case EQ:
|
||||
found = nextCharacter('=');
|
||||
break;
|
||||
case NULL:
|
||||
found = nextConstant("null");
|
||||
break;
|
||||
case EOF:
|
||||
found = index >= pathSegment.length();
|
||||
break;
|
||||
|
||||
// Identifiers
|
||||
case ODataIdentifier:
|
||||
found = nextODataIdentifier();
|
||||
break;
|
||||
case QualifiedName:
|
||||
found = nextQualifiedName();
|
||||
break;
|
||||
case ParameterAliasName:
|
||||
found = nextParameterAliasName();
|
||||
break;
|
||||
|
||||
// Primitive Values
|
||||
case PrimitiveBooleanValue:
|
||||
found = nextBooleanValue();
|
||||
break;
|
||||
case PrimitiveStringValue:
|
||||
found = nextStringValue();
|
||||
break;
|
||||
case PrimitiveIntegerValue:
|
||||
found = nextIntegerValue(true);
|
||||
break;
|
||||
case PrimitiveGuidValue:
|
||||
found = nextGuidValue();
|
||||
break;
|
||||
case PrimitiveDateValue:
|
||||
found = nextDateValue();
|
||||
break;
|
||||
case PrimitiveDateTimeOffsetValue:
|
||||
found = nextDateTimeOffsetValue();
|
||||
break;
|
||||
case PrimitiveTimeOfDayValue:
|
||||
found = nextTimeOfDayValue();
|
||||
break;
|
||||
case PrimitiveDecimalValue:
|
||||
found = nextDecimalValue();
|
||||
break;
|
||||
case PrimitiveDoubleValue:
|
||||
found = nextDoubleValue();
|
||||
break;
|
||||
case PrimitiveDurationValue:
|
||||
found = nextDurationValue();
|
||||
break;
|
||||
case PrimitiveBinaryValue:
|
||||
found = nextBinaryValue();
|
||||
break;
|
||||
case PrimitiveEnumValue:
|
||||
found = nextEnumValue();
|
||||
break;
|
||||
|
||||
// Primitive Values
|
||||
case jsonArrayOrObject:
|
||||
found = nextJsonArrayOrObject();
|
||||
break;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
startIndex = previousIndex;
|
||||
} else {
|
||||
index = previousIndex;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
private boolean nextConstant(final String constant) {
|
||||
if (pathSegment.startsWith(constant, index)) {
|
||||
index += constant.length();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nextConstantIgnoreCase(final String constant) {
|
||||
final int length = constant.length();
|
||||
if (index + length <= pathSegment.length()
|
||||
&& constant.equalsIgnoreCase(pathSegment.substring(index, index + length))) {
|
||||
index += length;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves past the given character if found; otherwise leaves the index unchanged.
|
||||
* @return whether the given character has been found at the current index
|
||||
*/
|
||||
private boolean nextCharacter(final char character) {
|
||||
if (index < pathSegment.length() && pathSegment.charAt(index) == character) {
|
||||
index++;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves past the next character if it is in the given character range;
|
||||
* otherwise leaves the index unchanged.
|
||||
* @return whether the given character has been found at the current index
|
||||
*/
|
||||
private boolean nextCharacterRange(final char from, final char to) {
|
||||
if (index < pathSegment.length()) {
|
||||
final char code = pathSegment.charAt(index);
|
||||
if (code >= from && code <= to) {
|
||||
index++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves past a digit character ('0' to '9') if found; otherwise leaves the index unchanged.
|
||||
* @return whether a digit character has been found at the current index
|
||||
*/
|
||||
private boolean nextDigit() {
|
||||
return nextCharacterRange('0', '9');
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves past a hexadecimal digit character ('0' to '9', 'A' to 'F', or 'a' to 'f') if found;
|
||||
* otherwise leaves the index unchanged.
|
||||
* @return whether a hexadecimal digit character has been found at the current index
|
||||
*/
|
||||
private boolean nextHexDigit() {
|
||||
return nextCharacterRange('0', '9') || nextCharacterRange('A', 'F') || nextCharacterRange('a', 'f');
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves past a base64 character ('0' to '9', 'A' to 'Z', 'a' to 'z', '-', or '_') if found;
|
||||
* otherwise leaves the index unchanged.
|
||||
* @return whether a base64 character has been found at the current index
|
||||
*/
|
||||
private boolean nextBase64() {
|
||||
return nextCharacterRange('0', '9') || nextCharacterRange('A', 'Z') || nextCharacterRange('a', 'z')
|
||||
|| nextCharacter('-') || nextCharacter('_');
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves past a sign character ('+' or '-') if found; otherwise leaves the index unchanged.
|
||||
* @return whether a sign character has been found at the current index
|
||||
*/
|
||||
private boolean nextSign() {
|
||||
return nextCharacter('+') || nextCharacter('-');
|
||||
}
|
||||
|
||||
private boolean nextODataIdentifier() {
|
||||
int count = 0;
|
||||
if (index < pathSegment.length()) {
|
||||
int code = pathSegment.codePointAt(index);
|
||||
if (Character.isUnicodeIdentifierStart(code) || code == '_') {
|
||||
count++;
|
||||
// Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
|
||||
index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
|
||||
while (index < pathSegment.length() && count < 128) {
|
||||
code = pathSegment.codePointAt(index);
|
||||
if (Character.isUnicodeIdentifierPart(code) && !Character.isISOControl(code)) {
|
||||
count++;
|
||||
// Unicode characters outside of the Basic Multilingual Plane are represented as two Java characters.
|
||||
index += Character.isSupplementaryCodePoint(code) ? 2 : 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
private boolean nextQualifiedName() {
|
||||
int count = 0;
|
||||
do {
|
||||
if (nextODataIdentifier()) {
|
||||
count++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} while (nextCharacter('.'));
|
||||
return count >= 2;
|
||||
}
|
||||
|
||||
private boolean nextParameterAliasName() {
|
||||
return nextCharacter('@') && nextODataIdentifier();
|
||||
}
|
||||
|
||||
private boolean nextBooleanValue() {
|
||||
return nextConstantIgnoreCase("true") || nextConstantIgnoreCase("false");
|
||||
}
|
||||
|
||||
private boolean nextStringValue() {
|
||||
if (!nextCharacter('\'')) {
|
||||
return false;
|
||||
}
|
||||
while (index < pathSegment.length()) {
|
||||
if (pathSegment.charAt(index) == '\'') {
|
||||
// If a single quote is followed by another single quote,
|
||||
// it represents one single quote within the string literal,
|
||||
// otherwise it marks the end of the string literal.
|
||||
if (index + 1 < pathSegment.length() && pathSegment.charAt(index + 1) == '\'') {
|
||||
index++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return nextCharacter('\'');
|
||||
}
|
||||
|
||||
private boolean nextIntegerValue(final boolean signed) {
|
||||
if (signed) {
|
||||
nextSign();
|
||||
}
|
||||
boolean hasDigits = false;
|
||||
while (nextDigit()) {
|
||||
hasDigits = true;
|
||||
}
|
||||
return hasDigits;
|
||||
}
|
||||
|
||||
/** Finds and returns only decimal-number tokens with a fractional part.
|
||||
* Whole numbers must be found with {@link #nextIntegerValue()}.
|
||||
*/
|
||||
private boolean nextDecimalValue() {
|
||||
return nextIntegerValue(true) && nextCharacter('.') && nextIntegerValue(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns only floating-point-number tokens with an exponential part
|
||||
* and the special three constants "NaN", "-INF", and "INF".
|
||||
* Whole numbers must be found with {@link #nextIntegerValue()}.
|
||||
* Decimal numbers must be found with {@link #nextDecimalValue()}.
|
||||
*/
|
||||
private boolean nextDoubleValue() {
|
||||
if (nextConstant("NaN") || nextConstant("-INF") || nextConstant("INF")) {
|
||||
return true;
|
||||
} else {
|
||||
if (!nextIntegerValue(true)) {
|
||||
return false;
|
||||
}
|
||||
if (nextCharacter('.') && !nextIntegerValue(false)) {
|
||||
return false;
|
||||
}
|
||||
return (nextCharacter('E') || nextCharacter('e')) && nextIntegerValue(true);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nextGuidValue() {
|
||||
return nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextCharacter('-')
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextCharacter('-')
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextCharacter('-')
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextCharacter('-')
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit()
|
||||
&& nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit();
|
||||
}
|
||||
|
||||
private boolean nextYear() {
|
||||
nextCharacter('-');
|
||||
if (nextCharacter('0')) {
|
||||
return nextDigit() && nextDigit() && nextDigit();
|
||||
} else if (nextCharacterRange('1', '9')) {
|
||||
int count = 0;
|
||||
while (nextDigit()) {
|
||||
count++;
|
||||
}
|
||||
return count >= 3;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nextDateValue() {
|
||||
return nextYear()
|
||||
&& nextCharacter('-')
|
||||
&& (nextCharacter('0') && nextCharacterRange('1', '9')
|
||||
|| nextCharacter('1') && nextCharacterRange('0', '2'))
|
||||
&& nextCharacter('-')
|
||||
&& (nextCharacter('0') && nextCharacterRange('1', '9')
|
||||
|| nextCharacterRange('1', '2') && nextDigit()
|
||||
|| nextCharacter('3') && nextCharacterRange('0', '1'));
|
||||
}
|
||||
|
||||
private boolean nextHours() {
|
||||
return nextCharacterRange('0', '1') && nextDigit()
|
||||
|| nextCharacter('2') && nextCharacterRange('0', '3');
|
||||
}
|
||||
|
||||
private boolean nextMinutesOrSeconds() {
|
||||
return nextCharacterRange('0', '5') && nextDigit();
|
||||
}
|
||||
|
||||
private boolean nextDateTimeOffsetValue() {
|
||||
return nextDateValue()
|
||||
&& (nextCharacter('T') || nextCharacter('t'))
|
||||
&& nextTimeOfDayValue()
|
||||
&& (nextCharacter('Z')
|
||||
|| nextCharacter('z')
|
||||
|| nextSign() && nextHours() && nextCharacter(':') && nextMinutesOrSeconds());
|
||||
}
|
||||
|
||||
private boolean nextTimeOfDayValue() {
|
||||
if (nextHours() && nextCharacter(':') && nextMinutesOrSeconds()) {
|
||||
if (nextCharacter(':')) {
|
||||
if (nextMinutesOrSeconds()) {
|
||||
if (nextCharacter('.') && !nextIntegerValue(false)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nextDurationValue() {
|
||||
if (nextConstantIgnoreCase("duration") && nextCharacter('\'')) {
|
||||
nextSign();
|
||||
if (nextCharacter('P') || nextCharacter('p')) {
|
||||
if (nextIntegerValue(false)) {
|
||||
if (!(nextCharacter('D') || nextCharacter('d'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (nextCharacter('T') || nextCharacter('t')) {
|
||||
boolean hasNumber = false;
|
||||
if (nextIntegerValue(false)) {
|
||||
hasNumber = true;
|
||||
if (nextCharacter('H') || nextCharacter('h')) {
|
||||
hasNumber = false;
|
||||
}
|
||||
}
|
||||
if (hasNumber || nextIntegerValue(false)) {
|
||||
hasNumber = true;
|
||||
if (nextCharacter('M') || nextCharacter('m')) {
|
||||
hasNumber = false;
|
||||
}
|
||||
}
|
||||
if (hasNumber || nextIntegerValue(false)) {
|
||||
if (nextCharacter('.')) {
|
||||
if (!nextIntegerValue(false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!(nextCharacter('S') || nextCharacter('s'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextCharacter('\'');
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean nextBinaryValue() {
|
||||
if (nextConstantIgnoreCase("binary") && nextCharacter('\'')) {
|
||||
int lastGoodIndex = index;
|
||||
while (nextBase64() && nextBase64() && nextBase64() && nextBase64()) {
|
||||
lastGoodIndex += 4;
|
||||
}
|
||||
index = lastGoodIndex;
|
||||
if (nextBase64() && nextBase64()
|
||||
&& (nextCharacter('A') || nextCharacter('E') || nextCharacter('I') || nextCharacter('M')
|
||||
|| nextCharacter('Q') || nextCharacter('U') || nextCharacter('Y') || nextCharacter('c')
|
||||
|| nextCharacter('g') || nextCharacter('k') || nextCharacter('o') || nextCharacter('s')
|
||||
|| nextCharacter('w') || nextCharacter('0') || nextCharacter('4') || nextCharacter('8'))) {
|
||||
nextCharacter('=');
|
||||
} else {
|
||||
index = lastGoodIndex;
|
||||
if (nextBase64()) {
|
||||
if (nextCharacter('A') || nextCharacter('Q') || nextCharacter('g') || nextCharacter('w')) {
|
||||
nextConstant("==");
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextCharacter('\'');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean nextEnumValue() {
|
||||
if (nextQualifiedName() && nextCharacter('\'')) {
|
||||
do {
|
||||
if (!(nextODataIdentifier() || nextIntegerValue(true))) {
|
||||
return false;
|
||||
}
|
||||
} while (nextCharacter(','));
|
||||
return nextCharacter('\'');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean nextJsonString() {
|
||||
if (nextCharacter('"')) {
|
||||
do {
|
||||
if (nextCharacter('\\')) {
|
||||
if (!(nextCharacter('b') || nextCharacter('t')
|
||||
|| nextCharacter('n') || nextCharacter('f') || nextCharacter('r')
|
||||
|| nextCharacter('"') || nextCharacter('/') || nextCharacter('\\')
|
||||
|| nextCharacter('u') && nextHexDigit() && nextHexDigit() && nextHexDigit() && nextHexDigit())) {
|
||||
return false;
|
||||
}
|
||||
} else if (nextCharacter('"')) {
|
||||
return true;
|
||||
} else {
|
||||
index++;
|
||||
}
|
||||
} while (index < pathSegment.length());
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean nextJsonValue() {
|
||||
return nextConstant("null") || nextConstant("true") || nextConstant("false")
|
||||
// If a double or decimal number is not found, the index must be reset; the internal methods don't do that.
|
||||
|| next(TokenKind.PrimitiveDoubleValue) || next(TokenKind.PrimitiveDecimalValue) || nextIntegerValue(true)
|
||||
|| nextJsonString()
|
||||
|| nextJsonArrayOrObject();
|
||||
}
|
||||
|
||||
private boolean nextJsonMember() {
|
||||
return nextJsonString() && nextCharacter(':') && nextJsonValue();
|
||||
}
|
||||
|
||||
private boolean nextJsonArrayOrObject() {
|
||||
if (nextCharacter('[')) {
|
||||
if (nextJsonValue()) {
|
||||
while (nextCharacter(',')) {
|
||||
if (!nextJsonValue()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextCharacter(']');
|
||||
} else if (nextCharacter('{')) {
|
||||
if (nextJsonMember()) {
|
||||
while (nextCharacter(',')) {
|
||||
if (!nextJsonMember()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nextCharacter('}');
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,6 @@ import java.util.Map;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityType;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunction;
|
||||
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
|
||||
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
@ -223,14 +222,7 @@ public class UriValidator {
|
||||
|
||||
private RowIndexForUriType rowIndexForResourceKind(final UriInfo uriInfo) throws UriValidationException {
|
||||
RowIndexForUriType idx;
|
||||
|
||||
final int nonComposableFunctionIndex = getIndexOfLastNonComposableFunction(uriInfo);
|
||||
if(nonComposableFunctionIndex != -1 && (uriInfo.getUriResourceParts().size() - 1) > nonComposableFunctionIndex) {
|
||||
throw new UriValidationException("Non composable functions followed by further resource parts are not allowed",
|
||||
UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH,
|
||||
uriInfo.getUriResourceParts().get(nonComposableFunctionIndex + 1).getSegmentValue());
|
||||
}
|
||||
|
||||
|
||||
int lastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 1;
|
||||
UriResource lastPathSegment = uriInfo.getUriResourceParts().get(lastPathSegmentIndex);
|
||||
|
||||
@ -249,11 +241,7 @@ public class UriValidator {
|
||||
idx = rowIndexForEntitySet(lastPathSegment);
|
||||
break;
|
||||
case function:
|
||||
if(nonComposableFunctionIndex == -1) {
|
||||
idx = rowIndexForFunction(lastPathSegment);
|
||||
} else {
|
||||
idx = RowIndexForUriType.none;
|
||||
}
|
||||
idx = rowIndexForFunction(lastPathSegment);
|
||||
break;
|
||||
case primitiveProperty:
|
||||
idx = rowIndexForPrimitiveProperty(lastPathSegment);
|
||||
@ -278,21 +266,6 @@ public class UriValidator {
|
||||
return idx;
|
||||
}
|
||||
|
||||
private int getIndexOfLastNonComposableFunction(final UriInfo uriInfo) {
|
||||
for(int i = 0; i < uriInfo.getUriResourceParts().size(); i++) {
|
||||
final UriResource resourcePath = uriInfo.getUriResourceParts().get(i);
|
||||
|
||||
if(resourcePath instanceof UriResourceFunction) {
|
||||
final UriResourceFunction resourceFuntion = (UriResourceFunction) resourcePath;
|
||||
if(!resourceFuntion.getFunction().isComposable()) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private RowIndexForUriType rowIndexForValue(final UriInfo uriInfo) throws UriValidationException {
|
||||
RowIndexForUriType idx;
|
||||
int secondLastPathSegmentIndex = uriInfo.getUriResourceParts().size() - 2;
|
||||
@ -309,9 +282,7 @@ public class UriValidator {
|
||||
break;
|
||||
case function:
|
||||
UriResourceFunction uriFunction = (UriResourceFunction) secondLastPathSegment;
|
||||
final EdmFunctionImport functionImport = uriFunction.getFunctionImport();
|
||||
final EdmFunction function = functionImport == null ?
|
||||
uriFunction.getFunction() : functionImport.getUnboundFunctions().get(0);
|
||||
final EdmFunction function = uriFunction.getFunction();
|
||||
idx = function.getReturnType().getType().getKind() == EdmTypeKind.ENTITY ?
|
||||
RowIndexForUriType.mediaStream : RowIndexForUriType.propertyPrimitiveValue;
|
||||
break;
|
||||
@ -351,32 +322,33 @@ public class UriValidator {
|
||||
}
|
||||
|
||||
private RowIndexForUriType rowIndexForFunction(final UriResource lastPathSegment) throws UriValidationException {
|
||||
RowIndexForUriType idx;
|
||||
UriResourceFunction urf = (UriResourceFunction) lastPathSegment;
|
||||
EdmReturnType rt = urf.getFunction().getReturnType();
|
||||
final UriResourceFunction uriFunction = (UriResourceFunction) lastPathSegment;
|
||||
final EdmReturnType returnType = uriFunction.getFunction().getReturnType();
|
||||
|
||||
if(!urf.getFunction().isComposable()) {
|
||||
if (!uriFunction.getFunction().isComposable()) {
|
||||
return RowIndexForUriType.none;
|
||||
}
|
||||
|
||||
|
||||
switch (rt.getType().getKind()) {
|
||||
|
||||
RowIndexForUriType idx;
|
||||
switch (returnType.getType().getKind()) {
|
||||
case ENTITY:
|
||||
idx = rt.isCollection() && urf.getKeyPredicates().isEmpty() ?
|
||||
idx = returnType.isCollection() && uriFunction.getKeyPredicates().isEmpty() ?
|
||||
RowIndexForUriType.entitySet : RowIndexForUriType.entity;
|
||||
break;
|
||||
case PRIMITIVE:
|
||||
case ENUM:
|
||||
case DEFINITION:
|
||||
idx = rt.isCollection() ? RowIndexForUriType.propertyPrimitiveCollection : RowIndexForUriType.propertyPrimitive;
|
||||
idx = returnType.isCollection() ? RowIndexForUriType.propertyPrimitiveCollection :
|
||||
RowIndexForUriType.propertyPrimitive;
|
||||
break;
|
||||
case COMPLEX:
|
||||
idx = rt.isCollection() ? RowIndexForUriType.propertyComplexCollection : RowIndexForUriType.propertyComplex;
|
||||
idx = returnType.isCollection() ? RowIndexForUriType.propertyComplexCollection :
|
||||
RowIndexForUriType.propertyComplex;
|
||||
break;
|
||||
default:
|
||||
throw new UriValidationException("Unsupported function return type: " + rt.getType().getKind(),
|
||||
throw new UriValidationException("Unsupported function return type: " + returnType.getType().getKind(),
|
||||
UriValidationException.MessageKeys.UNSUPPORTED_FUNCTION_RETURN_TYPE,
|
||||
rt.getType().getKind().toString());
|
||||
returnType.getType().getKind().toString());
|
||||
}
|
||||
|
||||
return idx;
|
||||
@ -447,9 +419,7 @@ public class UriValidator {
|
||||
break;
|
||||
case function:
|
||||
final UriResourceFunction uriFunction = (UriResourceFunction) secondLastPathSegment;
|
||||
final EdmFunctionImport functionImport = uriFunction.getFunctionImport();
|
||||
final EdmFunction function = functionImport == null ?
|
||||
uriFunction.getFunction() : functionImport.getUnboundFunctions().get(0);
|
||||
final EdmFunction function = uriFunction.getFunction();
|
||||
final EdmType returnType = function.getReturnType().getType();
|
||||
switch (returnType.getKind()) {
|
||||
case ENTITY:
|
||||
@ -560,8 +530,8 @@ public class UriValidator {
|
||||
private void validateParameters(final UriInfo uriInfo) throws UriValidationException {
|
||||
for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
|
||||
final boolean isFunction = pathSegment.getKind() == UriResourceKind.function;
|
||||
|
||||
if(isFunction) {
|
||||
|
||||
if (isFunction) {
|
||||
final UriResourceFunction functionPathSegement = (UriResourceFunction) pathSegment;
|
||||
final EdmFunction edmFuntion = functionPathSegement.getFunction();
|
||||
|
||||
@ -613,7 +583,7 @@ public class UriValidator {
|
||||
for (UriResource pathSegment : uriInfo.getUriResourceParts()) {
|
||||
final boolean isEntitySet = pathSegment.getKind() == UriResourceKind.entitySet;
|
||||
final boolean isEntityColFunction = isEntityColFunction(pathSegment);
|
||||
|
||||
|
||||
if (isEntitySet || pathSegment.getKind() == UriResourceKind.navigationProperty || isEntityColFunction) {
|
||||
final List<UriParameter> keyPredicates = isEntitySet ?
|
||||
((UriResourceEntitySet) pathSegment).getKeyPredicates() :
|
||||
@ -680,7 +650,7 @@ public class UriValidator {
|
||||
}
|
||||
|
||||
private boolean isEntityColFunction(final UriResource pathSegment) {
|
||||
if(pathSegment.getKind() == UriResourceKind.function) {
|
||||
if (pathSegment.getKind() == UriResourceKind.function) {
|
||||
final UriResourceFunction resourceFunction = (UriResourceFunction) pathSegment;
|
||||
final EdmReturnType returnType = resourceFunction.getFunction().getReturnType();
|
||||
|
||||
@ -689,7 +659,7 @@ public class UriValidator {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void validatePropertyOperations(final UriInfo uriInfo, final HttpMethod method)
|
||||
throws UriValidationException {
|
||||
final List<UriResource> parts = uriInfo.getUriResourceParts();
|
||||
|
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.apache.olingo.server.core.uri.parser.UriTokenizer.TokenKind;
|
||||
import org.junit.Test;
|
||||
|
||||
public class UriTokenizerTest {
|
||||
|
||||
@Test
|
||||
public void nullOK() {
|
||||
assertFalse(new UriTokenizer(null).next(null));
|
||||
assertTrue(new UriTokenizer(null).next(TokenKind.EOF));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constants() {
|
||||
final UriTokenizer tokenizer = new UriTokenizer("$ref");
|
||||
assertTrue(tokenizer.next(TokenKind.REF));
|
||||
assertEquals("$ref", tokenizer.getText());
|
||||
assertTrue(tokenizer.next(TokenKind.EOF));
|
||||
assertTrue(tokenizer.next(TokenKind.EOF));
|
||||
|
||||
assertTrue(new UriTokenizer("$value").next(TokenKind.VALUE));
|
||||
assertTrue(new UriTokenizer("$count").next(TokenKind.COUNT));
|
||||
assertTrue(new UriTokenizer("$crossjoin").next(TokenKind.CROSSJOIN));
|
||||
assertTrue(new UriTokenizer("null").next(TokenKind.NULL));
|
||||
|
||||
wrongToken(TokenKind.REF, "$ref", 'x');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sequence() {
|
||||
final UriTokenizer tokenizer = new UriTokenizer("(A=1,B=2);");
|
||||
assertTrue(tokenizer.next(TokenKind.OPEN));
|
||||
assertFalse(tokenizer.next(TokenKind.OPEN));
|
||||
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
|
||||
assertEquals("A", tokenizer.getText());
|
||||
assertTrue(tokenizer.next(TokenKind.EQ));
|
||||
assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
|
||||
assertEquals("1", tokenizer.getText());
|
||||
assertTrue(tokenizer.next(TokenKind.COMMA));
|
||||
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
|
||||
assertEquals("B", tokenizer.getText());
|
||||
assertTrue(tokenizer.next(TokenKind.EQ));
|
||||
assertTrue(tokenizer.next(TokenKind.PrimitiveIntegerValue));
|
||||
assertEquals("2", tokenizer.getText());
|
||||
assertFalse(tokenizer.next(TokenKind.EOF));
|
||||
assertTrue(tokenizer.next(TokenKind.CLOSE));
|
||||
assertTrue(tokenizer.next(TokenKind.SEMI));
|
||||
assertTrue(tokenizer.next(TokenKind.EOF));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void identifier() {
|
||||
assertTrue(new UriTokenizer("name").next(TokenKind.ODataIdentifier));
|
||||
assertTrue(new UriTokenizer("_name").next(TokenKind.ODataIdentifier));
|
||||
assertFalse(new UriTokenizer("1name").next(TokenKind.ODataIdentifier));
|
||||
assertFalse(new UriTokenizer("").next(TokenKind.ODataIdentifier));
|
||||
|
||||
final String outsideBmpLetter = String.valueOf(Character.toChars(0x10330));
|
||||
UriTokenizer tokenizer = new UriTokenizer(
|
||||
outsideBmpLetter + "name1\u0300a\u0600b\uFE4F" + outsideBmpLetter + "end\b");
|
||||
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
|
||||
assertEquals(outsideBmpLetter + "name1\u0300a\u0600b\uFE4F" + outsideBmpLetter + "end", tokenizer.getText());
|
||||
|
||||
// Identifiers consist of up to 128 characters. Check that the identifier does not have more characters.
|
||||
final String name = "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch"; // Do you know this village?
|
||||
tokenizer = new UriTokenizer(name + '_' + name + "_0123456789X");
|
||||
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
|
||||
assertEquals(name + '_' + name + "_0123456789", tokenizer.getText());
|
||||
tokenizer.next(TokenKind.ODataIdentifier);
|
||||
assertEquals("X", tokenizer.getText());
|
||||
|
||||
wrongToken(TokenKind.ODataIdentifier, "_", '.');
|
||||
wrongToken(TokenKind.ODataIdentifier, "_", ',');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void qualifiedName() {
|
||||
assertTrue(new UriTokenizer("namespace.name").next(TokenKind.QualifiedName));
|
||||
|
||||
final UriTokenizer tokenizer = new UriTokenizer("multi.part.namespace.name");
|
||||
assertTrue(tokenizer.next(TokenKind.QualifiedName));
|
||||
assertTrue(tokenizer.next(TokenKind.EOF));
|
||||
|
||||
assertFalse(new UriTokenizer("name").next(TokenKind.QualifiedName));
|
||||
assertFalse(new UriTokenizer("namespace..name").next(TokenKind.QualifiedName));
|
||||
assertFalse(new UriTokenizer("").next(TokenKind.QualifiedName));
|
||||
wrongToken(TokenKind.QualifiedName, "namespace._", ',');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void alias() {
|
||||
assertTrue(new UriTokenizer("@name").next(TokenKind.ParameterAliasName));
|
||||
assertTrue(new UriTokenizer("@_name").next(TokenKind.ParameterAliasName));
|
||||
assertFalse(new UriTokenizer("name").next(TokenKind.ParameterAliasName));
|
||||
assertFalse(new UriTokenizer("@").next(TokenKind.ParameterAliasName));
|
||||
assertFalse(new UriTokenizer("@1").next(TokenKind.ParameterAliasName));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void booleanValue() {
|
||||
assertTrue(new UriTokenizer("true").next(TokenKind.PrimitiveBooleanValue));
|
||||
assertTrue(new UriTokenizer("tRuE").next(TokenKind.PrimitiveBooleanValue));
|
||||
assertTrue(new UriTokenizer("false").next(TokenKind.PrimitiveBooleanValue));
|
||||
assertTrue(new UriTokenizer("False").next(TokenKind.PrimitiveBooleanValue));
|
||||
|
||||
wrongToken(TokenKind.PrimitiveBooleanValue, "true", 'x');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void string() {
|
||||
assertTrue(new UriTokenizer("'ABC'").next(TokenKind.PrimitiveStringValue));
|
||||
assertTrue(new UriTokenizer("'€\uFDFC'").next(TokenKind.PrimitiveStringValue));
|
||||
assertTrue(new UriTokenizer('\'' + String.valueOf(Character.toChars(0x1F603)) + '\'')
|
||||
.next(TokenKind.PrimitiveStringValue));
|
||||
|
||||
final UriTokenizer tokenizer = new UriTokenizer("'AB''''C'''D");
|
||||
assertTrue(tokenizer.next(TokenKind.PrimitiveStringValue));
|
||||
assertEquals("'AB''''C'''", tokenizer.getText());
|
||||
assertTrue(tokenizer.next(TokenKind.ODataIdentifier));
|
||||
assertEquals("D", tokenizer.getText());
|
||||
|
||||
assertFalse(new UriTokenizer("A").next(TokenKind.PrimitiveStringValue));
|
||||
assertFalse(new UriTokenizer("'A").next(TokenKind.PrimitiveStringValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void integer() {
|
||||
assertTrue(new UriTokenizer("1").next(TokenKind.PrimitiveIntegerValue));
|
||||
assertTrue(new UriTokenizer("1.").next(TokenKind.PrimitiveIntegerValue));
|
||||
assertFalse(new UriTokenizer(".1").next(TokenKind.PrimitiveIntegerValue));
|
||||
assertTrue(new UriTokenizer("-1").next(TokenKind.PrimitiveIntegerValue));
|
||||
assertTrue(new UriTokenizer("1234567890").next(TokenKind.PrimitiveIntegerValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void guid() {
|
||||
assertTrue(new UriTokenizer("12345678-abcd-ef12-1234-567890ABCDEF").next(TokenKind.PrimitiveGuidValue));
|
||||
wrongToken(TokenKind.PrimitiveGuidValue, "12345678-1234-1234-1234-123456789ABC", 'G');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void date() {
|
||||
assertTrue(new UriTokenizer("12345-12-25").next(TokenKind.PrimitiveDateValue));
|
||||
assertTrue(new UriTokenizer("-0001-12-24").next(TokenKind.PrimitiveDateValue));
|
||||
assertFalse(new UriTokenizer("1234-13-01").next(TokenKind.PrimitiveDateValue));
|
||||
assertFalse(new UriTokenizer("1234-12-32").next(TokenKind.PrimitiveDateValue));
|
||||
assertFalse(new UriTokenizer("123-01-01").next(TokenKind.PrimitiveDateValue));
|
||||
assertFalse(new UriTokenizer("1234-00-01").next(TokenKind.PrimitiveDateValue));
|
||||
assertFalse(new UriTokenizer("1234-01-00").next(TokenKind.PrimitiveDateValue));
|
||||
wrongToken(TokenKind.PrimitiveDateValue, "2000-12-29", 'A');
|
||||
wrongToken(TokenKind.PrimitiveDateValue, "0001-01-01", 'A');
|
||||
wrongToken(TokenKind.PrimitiveDateValue, "-12345-01-31", 'A');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void dateTimeOffset() {
|
||||
assertTrue(new UriTokenizer("1234-12-25T11:12:13.456Z").next(TokenKind.PrimitiveDateTimeOffsetValue));
|
||||
assertTrue(new UriTokenizer("-1234-12-25t01:12z").next(TokenKind.PrimitiveDateTimeOffsetValue));
|
||||
assertTrue(new UriTokenizer("-1234-12-25T21:22:23+01:00").next(TokenKind.PrimitiveDateTimeOffsetValue));
|
||||
assertTrue(new UriTokenizer("1234-12-25T11:12:13-00:30").next(TokenKind.PrimitiveDateTimeOffsetValue));
|
||||
assertFalse(new UriTokenizer("1234-10-01").next(TokenKind.PrimitiveDateTimeOffsetValue));
|
||||
wrongToken(TokenKind.PrimitiveDateTimeOffsetValue, "-1234-12-25T11:12:13.456+01:00", 'P');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void timeOfDay() {
|
||||
assertTrue(new UriTokenizer("11:12:13").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertTrue(new UriTokenizer("11:12:13.456").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("24:00:00").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("01:60:00").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("01:00:60").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("01:00:00.").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("0:02:03").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("01:0:03").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
assertFalse(new UriTokenizer("01:02:0").next(TokenKind.PrimitiveTimeOfDayValue));
|
||||
wrongToken(TokenKind.PrimitiveTimeOfDayValue, "11:12", '-');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void decimal() {
|
||||
assertTrue(new UriTokenizer("1.2").next(TokenKind.PrimitiveDecimalValue));
|
||||
assertFalse(new UriTokenizer(".1").next(TokenKind.PrimitiveDecimalValue));
|
||||
assertTrue(new UriTokenizer("-12.34").next(TokenKind.PrimitiveDecimalValue));
|
||||
assertTrue(new UriTokenizer("1234567890.0123456789").next(TokenKind.PrimitiveDecimalValue));
|
||||
assertFalse(new UriTokenizer("0,1").next(TokenKind.PrimitiveDecimalValue));
|
||||
assertFalse(new UriTokenizer("0..1").next(TokenKind.PrimitiveDecimalValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doubleValue() {
|
||||
assertTrue(new UriTokenizer("NaN").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertTrue(new UriTokenizer("-INF").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertTrue(new UriTokenizer("INF").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertFalse(new UriTokenizer("inf").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertTrue(new UriTokenizer("1.2E3").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertTrue(new UriTokenizer("-12.34e-05").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertTrue(new UriTokenizer("1E2").next(TokenKind.PrimitiveDoubleValue));
|
||||
assertFalse(new UriTokenizer("1.E2").next(TokenKind.PrimitiveDoubleValue));
|
||||
wrongToken(TokenKind.PrimitiveDoubleValue, "-12.34E+5", 'i');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void duration() {
|
||||
assertTrue(new UriTokenizer("duration'P'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("DURATION'P1D'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("duration'PT'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("duration'PT1H'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("duration'pt1M'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("duration'PT1S'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("duration'PT1.2s'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertTrue(new UriTokenizer("duration'-p1dt2h3m4.5s'").next(TokenKind.PrimitiveDurationValue));
|
||||
assertFalse(new UriTokenizer("-p1dt2h3m4.5s").next(TokenKind.PrimitiveDurationValue));
|
||||
assertFalse(new UriTokenizer("duration'-p1dt2h3m4.5s").next(TokenKind.PrimitiveDurationValue));
|
||||
assertFalse(new UriTokenizer("duration'2h3m4s'").next(TokenKind.PrimitiveDurationValue));
|
||||
wrongToken(TokenKind.PrimitiveDurationValue, "duration'P1DT2H3M4.5S'", ':');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void binary() {
|
||||
assertTrue(new UriTokenizer("binary''").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("Binary'bm93'").next(TokenKind.PrimitiveBinaryValue));
|
||||
|
||||
// all cases with three base64 characters (and one fill character) at the end
|
||||
assertTrue(new UriTokenizer("binary'QUA='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUE='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUI='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUM='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUQ='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUU='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUY='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUc='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUg='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUk='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUo='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUs='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QUw='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QU0='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QU4='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'QU8='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertFalse(new UriTokenizer("binary'QUB='").next(TokenKind.PrimitiveBinaryValue));
|
||||
|
||||
// all cases with two base64 characters (and two fill characters) at the end
|
||||
assertTrue(new UriTokenizer("BINARY'VGVzdA=='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'U-RnZQ=='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'Yg=='").next(TokenKind.PrimitiveBinaryValue));
|
||||
assertTrue(new UriTokenizer("binary'Yw=='").next(TokenKind.PrimitiveBinaryValue));
|
||||
|
||||
// without optional fill character
|
||||
assertTrue(new UriTokenizer("binary'T0RhdGE'").next(TokenKind.PrimitiveBinaryValue));
|
||||
|
||||
// special character '_' (the other, '-', already has been used above)
|
||||
assertTrue(new UriTokenizer("binary'V_ZydGVy'").next(TokenKind.PrimitiveBinaryValue));
|
||||
|
||||
wrongToken(TokenKind.PrimitiveBinaryValue, "binary'VGVzdA=='", '+');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enumValue() {
|
||||
assertTrue(new UriTokenizer("namespace.name'value'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertTrue(new UriTokenizer("namespace.name'flag1,flag2,-3'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("namespace.name'1flag'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("namespace.name'flag1,,flag2'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("namespace.name',value'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("namespace.name'value,'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("namespace.name''").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("'1'").next(TokenKind.PrimitiveEnumValue));
|
||||
assertFalse(new UriTokenizer("1").next(TokenKind.PrimitiveEnumValue));
|
||||
wrongToken(TokenKind.PrimitiveEnumValue, "namespace.name'_1,_2,3'", ';');
|
||||
}
|
||||
|
||||
@Test
|
||||
public void json() {
|
||||
// Empty string or JSON values are not allowed.
|
||||
assertFalse(new UriTokenizer("").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("1").next(TokenKind.jsonArrayOrObject));
|
||||
|
||||
// object with values
|
||||
assertTrue(new UriTokenizer("{}").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":0}").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":true}").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":false}").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":null}").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":\"value\"}").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":\"value\",\"name2\":null}").next(TokenKind.jsonArrayOrObject));
|
||||
|
||||
// array with values
|
||||
assertTrue(new UriTokenizer("[]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[1]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[true]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[false]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[null]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[\"value\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[\"\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[\"\\b\\t\\f\\r\\nn\\/\\\\x\\uFE4Fu\\\"\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[1,2.0,3.4E5]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("[\"value\",null]").next(TokenKind.jsonArrayOrObject));
|
||||
|
||||
// nesting
|
||||
assertTrue(new UriTokenizer("[{\"name\":\"value\"},{\"name\":\"value2\"}]").next(TokenKind.jsonArrayOrObject));
|
||||
assertTrue(new UriTokenizer("{\"name\":{\"name2\":\"value\"}}").next(TokenKind.jsonArrayOrObject));
|
||||
|
||||
// unbalanced opening and closing
|
||||
assertFalse(new UriTokenizer("{").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("}").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{]").next(TokenKind.jsonArrayOrObject));
|
||||
|
||||
// missing values
|
||||
assertFalse(new UriTokenizer("[1,]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[,1]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[1,,2]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[1,x]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{\"name\":1,}").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{,\"name\":1}").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{\"name\":1,,\"name2\":2}").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{\"name\":1,x}").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{\"name\":1,\"name2\"}").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("{\"name\":1,\"name2\":}").next(TokenKind.jsonArrayOrObject));
|
||||
|
||||
// wrong JSON strings
|
||||
assertFalse(new UriTokenizer("[\"a").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"a]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"a\"\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"\\x\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"\\ux\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"\\u1\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"\\u12x\"]").next(TokenKind.jsonArrayOrObject));
|
||||
assertFalse(new UriTokenizer("[\"\\u123x\"]").next(TokenKind.jsonArrayOrObject));
|
||||
}
|
||||
|
||||
private void wrongToken(final TokenKind kind, final String value, final char disturbCharacter) {
|
||||
assertFalse(new UriTokenizer(disturbCharacter + value).next(kind));
|
||||
|
||||
final UriTokenizer tokenizer = new UriTokenizer(value + disturbCharacter);
|
||||
assertTrue(tokenizer.next(kind));
|
||||
assertEquals(value, tokenizer.getText());
|
||||
|
||||
// Place the disturbing character at every position in the value string
|
||||
// and check that this leads to a failed token recognition.
|
||||
for (int index = 0; index < value.length(); index++) {
|
||||
assertFalse("Error at index " + index,
|
||||
new UriTokenizer(value.substring(0, index) + disturbCharacter + value.substring(index + 1)).next(kind));
|
||||
}
|
||||
}
|
||||
}
|
@ -31,7 +31,6 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SearchTokenizerTest {
|
||||
|
@ -29,7 +29,6 @@ import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
@ -44,8 +43,7 @@ public class DataProviderTest {
|
||||
private final Edm edm =
|
||||
oData.createServiceMetadata(new EdmTechProvider(), Collections.<EdmxReference> emptyList())
|
||||
.getEdm();
|
||||
private final EdmEntityContainer entityContainer = edm.getEntityContainer(
|
||||
new FullQualifiedName("olingo.odata.test1", "Container"));
|
||||
private final EdmEntityContainer entityContainer = edm.getEntityContainer();
|
||||
|
||||
private final EdmEntitySet esAllPrim = entityContainer.getEntitySet("ESAllPrim");
|
||||
private final EdmEntitySet esAllKey = entityContainer.getEntitySet("ESAllKey");
|
||||
|
@ -41,7 +41,7 @@ import org.apache.olingo.server.api.uri.UriResourceValue;
|
||||
import org.apache.olingo.server.core.etag.PreconditionsValidator;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
@ -49,7 +49,8 @@ import org.mockito.stubbing.Answer;
|
||||
|
||||
public class PreconditionsValidatorTest {
|
||||
|
||||
private static final Edm edm = OData.newInstance().createServiceMetadata(
|
||||
private static final OData odata = OData.newInstance();
|
||||
private static final Edm edm = odata.createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
|
||||
|
||||
// -------------- POSITIVE TESTS --------------------------------------------------------------------------------
|
||||
@ -140,7 +141,7 @@ public class PreconditionsValidatorTest {
|
||||
|
||||
@Test
|
||||
public void simpleEntityValueValidationNotActiveForMedia() throws Exception {
|
||||
final UriInfo uriInfo = new Parser().parseUri("ESMedia(1)/$value", null, null, edm);
|
||||
final UriInfo uriInfo = new Parser(edm, odata).parseUri("ESMedia(1)/$value", null, null);
|
||||
|
||||
CustomETagSupport support = mock(CustomETagSupport.class);
|
||||
when(support.hasETag(any(EdmBindingTarget.class))).thenReturn(true);
|
||||
@ -185,21 +186,17 @@ public class PreconditionsValidatorTest {
|
||||
assertFalse(mustValidate("SINav/NavPropertyETKeyNavOne/$ref", "ESKeyNav"));
|
||||
}
|
||||
|
||||
@Test(expected = UriParserSemanticException.class)
|
||||
public void resourceSegmentAfterActionMustLeadToUriParserException() throws Exception {
|
||||
mustValidate("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav/PropertyInt16", "ESKeyNav");
|
||||
}
|
||||
|
||||
@Test(expected = UriParserSemanticException.class)
|
||||
public void valueMustBeLastSegment() throws Exception {
|
||||
mustValidate("ESMedia(1)/$value/PropertyInt16", "ESMedia");
|
||||
@Test
|
||||
public void nonResourceMustBeIgnored() throws Exception {
|
||||
assertFalse(mustValidate("$all", null));
|
||||
}
|
||||
|
||||
private boolean mustValidate(final String uri, final String entitySetName)
|
||||
throws UriParserException, PreconditionException {
|
||||
final UriInfo uriInfo = new Parser().parseUri(uri, null, null, edm);
|
||||
throws UriParserException, UriValidationException, PreconditionException {
|
||||
final UriInfo uriInfo = new Parser(edm, odata).parseUri(uri, null, null);
|
||||
final List<UriResource> parts = uriInfo.getUriResourceParts();
|
||||
final boolean isMedia = parts.get(parts.size() - 1) instanceof UriResourceValue
|
||||
final boolean isMedia = parts.size() >= 2
|
||||
&& parts.get(parts.size() - 1) instanceof UriResourceValue
|
||||
&& parts.get(parts.size() - 2) instanceof UriResourceEntitySet;
|
||||
|
||||
CustomETagSupport support = mock(CustomETagSupport.class);
|
||||
|
@ -28,7 +28,6 @@ import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.uri.UriParameter;
|
||||
@ -45,8 +44,7 @@ public class ContextURLHelperTest {
|
||||
|
||||
private static final Edm edm = OData.newInstance().createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
|
||||
private static final EdmEntityContainer entityContainer = edm.getEntityContainer(
|
||||
new FullQualifiedName("olingo.odata.test1", "Container"));
|
||||
private static final EdmEntityContainer entityContainer = edm.getEntityContainer();
|
||||
|
||||
@Test
|
||||
public void buildSelect() throws Exception {
|
||||
|
@ -25,7 +25,6 @@ import org.apache.olingo.commons.api.data.ValueType;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.serializer.SerializerException;
|
||||
@ -40,8 +39,7 @@ public class UriHelperTest {
|
||||
private static final OData odata = OData.newInstance();
|
||||
private static final Edm edm = odata.createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
|
||||
private static final EdmEntityContainer container = edm.getEntityContainer(
|
||||
new FullQualifiedName("olingo.odata.test1", "Container"));
|
||||
private static final EdmEntityContainer container = edm.getEntityContainer();
|
||||
private static final UriHelper helper = odata.createUriHelper();
|
||||
private final DataProvider data = new DataProvider(odata, edm);
|
||||
|
||||
|
@ -86,7 +86,7 @@ public class UriResourceImplTest {
|
||||
|
||||
// action import
|
||||
impl = new UriResourceActionImpl();
|
||||
EdmActionImport actionImport = edm.getEntityContainer(null).getActionImport("AIRTCTTwoPrimParam");
|
||||
EdmActionImport actionImport = edm.getEntityContainer().getActionImport("AIRTCTTwoPrimParam");
|
||||
impl.setActionImport(actionImport);
|
||||
assertEquals(actionImport, impl.getActionImport());
|
||||
assertEquals(actionImport.getUnboundAction(), impl.getAction());
|
||||
@ -94,7 +94,7 @@ public class UriResourceImplTest {
|
||||
assertEquals("AIRTCTTwoPrimParam", impl.toString());
|
||||
assertEquals(actionImport.getUnboundAction().getReturnType().getType(), impl.getType());
|
||||
|
||||
actionImport = edm.getEntityContainer(null).getActionImport("AIRT");
|
||||
actionImport = edm.getEntityContainer().getActionImport("AIRT");
|
||||
impl.setActionImport(actionImport);
|
||||
assertFalse(impl.isCollection());
|
||||
assertNull(impl.getType());
|
||||
@ -184,7 +184,7 @@ public class UriResourceImplTest {
|
||||
UriResourceEntitySetImpl impl = new UriResourceEntitySetImpl();
|
||||
assertEquals(UriResourceKind.entitySet, impl.getKind());
|
||||
|
||||
EdmEntitySet entitySet = edm.getEntityContainer(null).getEntitySet("ESAllPrim");
|
||||
EdmEntitySet entitySet = edm.getEntityContainer().getEntitySet("ESAllPrim");
|
||||
impl.setEntitSet(entitySet);
|
||||
|
||||
assertEquals("ESAllPrim", impl.toString());
|
||||
@ -207,7 +207,7 @@ public class UriResourceImplTest {
|
||||
assertEquals("", impl.toString());
|
||||
|
||||
// function
|
||||
EdmFunction function = edm.getEntityContainer(null).getFunctionImport("FINRTInt16")
|
||||
EdmFunction function = edm.getEntityContainer().getFunctionImport("FINRTInt16")
|
||||
.getUnboundFunction(Collections.<String> emptyList());
|
||||
assertNotNull(function);
|
||||
impl.setFunction(function);
|
||||
@ -219,14 +219,14 @@ public class UriResourceImplTest {
|
||||
|
||||
// function import
|
||||
impl = new UriResourceFunctionImpl();
|
||||
EdmFunctionImport functionImport = edm.getEntityContainer(null).getFunctionImport("FINRTInt16");
|
||||
EdmFunctionImport functionImport = edm.getEntityContainer().getFunctionImport("FINRTInt16");
|
||||
impl.setFunctionImport(functionImport, Collections.<UriParameter> emptyList());
|
||||
assertEquals(functionImport, impl.getFunctionImport());
|
||||
assertEquals("FINRTInt16", impl.toString());
|
||||
|
||||
// function collection
|
||||
impl = new UriResourceFunctionImpl();
|
||||
functionImport = edm.getEntityContainer(null).getFunctionImport("FICRTCollESTwoKeyNavParam");
|
||||
functionImport = edm.getEntityContainer().getFunctionImport("FICRTCollESTwoKeyNavParam");
|
||||
assertNotNull(function);
|
||||
UriParameter parameter = new UriParameterImpl().setName("ParameterInt16");
|
||||
impl.setFunctionImport(functionImport, Collections.singletonList(parameter));
|
||||
@ -414,7 +414,7 @@ public class UriResourceImplTest {
|
||||
UriResourceSingletonImpl impl = new UriResourceSingletonImpl();
|
||||
assertEquals(UriResourceKind.singleton, impl.getKind());
|
||||
|
||||
EdmSingleton singleton = edm.getEntityContainer(null).getSingleton("SINav");
|
||||
EdmSingleton singleton = edm.getEntityContainer().getSingleton("SINav");
|
||||
EdmEntityType entityTypeBaseColl = edm.getEntityType(EntityTypeProvider.nameETBaseTwoKeyNav);
|
||||
impl.setSingleton(singleton);
|
||||
|
||||
|
@ -34,12 +34,10 @@ import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.format.ContentType;
|
||||
import org.apache.olingo.commons.core.Encoder;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriResourceKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
|
||||
@ -934,14 +932,20 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runCrossjoin() throws Exception {
|
||||
public void crossjoin() throws Exception {
|
||||
testUri.run("$crossjoin(ESKeyNav)")
|
||||
.isKind(UriInfoKind.crossjoin)
|
||||
.isCrossJoinEntityList(Arrays.asList("ESKeyNav"));
|
||||
|
||||
testUri.run("$crossjoin(ESKeyNav, ESTwoKeyNav)")
|
||||
testUri.run("$crossjoin(ESKeyNav,ESTwoKeyNav)")
|
||||
.isKind(UriInfoKind.crossjoin)
|
||||
.isCrossJoinEntityList(Arrays.asList("ESKeyNav", "ESTwoKeyNav"));
|
||||
|
||||
testUri.run("$crossjoin(ESTwoPrim,ESMixPrimCollComp)",
|
||||
"$filter=ESTwoPrim/PropertyString eq ESMixPrimCollComp/PropertyComp/PropertyString")
|
||||
.goFilter()
|
||||
.isBinary(BinaryOperatorKind.EQ)
|
||||
.is("<<ESTwoPrim/PropertyString> eq <ESMixPrimCollComp/PropertyComp/PropertyString>>");
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -951,6 +955,8 @@ public class TestFullResourcePath {
|
||||
testUri.runEx("$crossjoin()").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
testUri.runEx("$crossjoin(ESKeyNav, ESTwoKeyNav)/invalid")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$crossjoin(ESKeyNav)/$ref")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -982,15 +988,16 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runEsNameError() {
|
||||
public void esNameError() {
|
||||
|
||||
testUri.runEx("ESAllPrim/$count/$ref").isExSemantic(MessageKeys.ONLY_FOR_TYPED_PROPERTIES);
|
||||
testUri.runEx("ESAllPrim/$ref/$count").isExSemantic(MessageKeys.ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("ESAllPrim/$ref/invalid").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("ESAllPrim/$count/invalid").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("ESAllPrim/$count/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("ESAllPrim/$ref/$count").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("ESAllPrim/$ref/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("ESAllPrim/$count/invalid").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("ESAllPrim/PropertyString").isExSemantic(MessageKeys.PROPERTY_AFTER_COLLECTION);
|
||||
testUri.runEx("ESAllPrim(1)/whatever").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
|
||||
testUri.runEx("ESAllPrim(PropertyInt16)").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESAllPrim('1')").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESAllPrim(PropertyInt16)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
testUri.runEx("ESAllPrim(PropertyInt16=)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
testUri.runEx("ESAllPrim(PropertyInt16=1,Invalid='1')").isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
|
||||
@ -1023,8 +1030,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runResourcePathWithApostrophe() {
|
||||
// TODO Currently "'" is not allowed in OData identifiers, but the specification allows this character (Unicode Cf)
|
||||
public void resourcePathWithApostrophe() {
|
||||
testUri.runEx("ESAllPrim'").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
testUri.runEx("ESAllPrim'InvalidStuff").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
@ -1070,7 +1076,7 @@ public class TestFullResourcePath {
|
||||
.isKeyPredicate(0, "PropertyInt16", "0");
|
||||
|
||||
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterString='1',ParameterInt16=1)(PropertyInt16 eq 0)")
|
||||
.isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
// PropertyInt32 does not exist
|
||||
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterString='1',ParameterInt16=1)(PropertyInt32=0)")
|
||||
@ -1078,7 +1084,7 @@ public class TestFullResourcePath {
|
||||
|
||||
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterString='1',ParameterInt16=1)"
|
||||
+ "(PropertyInt16=0,PropertyInt16=1)")
|
||||
.isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
.isExValidation(UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY);
|
||||
|
||||
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterString='1',ParameterInt16=1)")
|
||||
.isKind(UriInfoKind.resource)
|
||||
@ -1117,13 +1123,13 @@ public class TestFullResourcePath {
|
||||
.isKeyPredicate(1, "PropertyString", "'1'");
|
||||
|
||||
testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)(PropertyInt16 eq 1)")
|
||||
.isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)(PropertyInt16=1)")
|
||||
.isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
|
||||
testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)(PropertyInt16=1,PropertyInt32=1,PropertyString='1')")
|
||||
.isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
|
||||
testUri.runEx("FICRTCollESTwoKeyNavParam(ParameterInt16=1)()")
|
||||
.isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
@ -1193,11 +1199,9 @@ public class TestFullResourcePath {
|
||||
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$skiptoken=5")
|
||||
.isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
|
||||
|
||||
// $search is currently not implemented. Please change this exception if the implementation is done.
|
||||
// FIXME (151106:mibo): check after finish of OLINGO-568
|
||||
// testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
|
||||
// .isExSemantic(MessageKeys.NOT_IMPLEMENTED);
|
||||
|
||||
testUri.runEx("FICRTCollETMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='1')", "$search=test")
|
||||
.isExValidation(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
|
||||
|
||||
testUri.run("ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim()")
|
||||
.isKind(UriInfoKind.resource)
|
||||
.goPath().first()
|
||||
@ -1296,8 +1300,8 @@ public class TestFullResourcePath {
|
||||
.isKeyPredicate(2, "KeyAlias2", "'3'")
|
||||
.isKeyPredicate(3, "KeyAlias3", "'4'");
|
||||
|
||||
testUri.runEx("ESTwoPrim(wrong)").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESTwoPrim(PropertyInt16=wrong)").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESTwoPrim('wrong')").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESTwoPrim(PropertyInt16='wrong')").isExSemantic(MessageKeys.INVALID_KEY_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -1794,7 +1798,7 @@ public class TestFullResourcePath {
|
||||
|
||||
@Test
|
||||
public void runEsNamePpNpRc() throws Exception {
|
||||
// checks for using referential constrains to fill missing keys
|
||||
// checks for using referential constraints to fill missing keys
|
||||
testUri.run("ESKeyNav(1)/NavPropertyETTwoKeyNavMany('2')").goPath()
|
||||
.first()
|
||||
.isEntitySet("ESKeyNav")
|
||||
@ -2037,7 +2041,6 @@ public class TestFullResourcePath {
|
||||
|
||||
@Test
|
||||
public void runFunctionImpEs() throws Exception {
|
||||
/**/
|
||||
testUri.run("FICRTESMixPrimCollCompTwoParam(ParameterInt16=1,ParameterString='2')")
|
||||
.isKind(UriInfoKind.resource).goPath()
|
||||
.first()
|
||||
@ -2805,8 +2808,8 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("$search currently not implemented")
|
||||
public void runDuplicatedSearchExpand() throws UriParserException, UriValidationException {
|
||||
@Ignore("$search in expand currently not implemented")
|
||||
public void duplicatedSearchExpand() throws Exception {
|
||||
testUri.runEx("ESKeyNav", "$expand=NavPropertyETKeyNavOne($search=Test;$search=Test)")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.DOUBLE_SYSTEM_QUERY_OPTION);
|
||||
}
|
||||
@ -2931,13 +2934,8 @@ public class TestFullResourcePath {
|
||||
testUri.run("$batch")
|
||||
.isKind(UriInfoKind.batch);
|
||||
|
||||
testUri.run("$crossjoin(ESKeyNav)")
|
||||
.isKind(UriInfoKind.crossjoin)
|
||||
.isCrossJoinEntityList(Arrays.asList("ESKeyNav"));
|
||||
|
||||
testUri.runEx("$metadata/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$batch/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$crossjoin(ESKeyNav)/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$all/$ref").isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
testUri.runEx("$entity/olingo.odata.test1.ETKeyNav/$ref")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.MUST_BE_LAST_SEGMENT);
|
||||
@ -3142,7 +3140,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilter() throws UriParserException {
|
||||
public void filter() throws Exception {
|
||||
|
||||
testFilter.runOnETTwoKeyNav("PropertyString")
|
||||
.is("<PropertyString>")
|
||||
@ -3684,7 +3682,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterProperties() throws UriParserException {
|
||||
public void filterProperties() throws Exception {
|
||||
testFilter.runOnETAllPrim("PropertyByte mod 0")
|
||||
.is("<<PropertyByte> mod <0>>");
|
||||
|
||||
@ -3849,7 +3847,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterPMethods() throws ExpressionVisitException, ODataApplicationException, UriParserException {
|
||||
public void filterPMethods() throws Exception {
|
||||
|
||||
testFilter.runOnETKeyNav("indexof(PropertyString,'47') eq 5")
|
||||
.is("<<indexof(<PropertyString>,<'47'>)> eq <5>>")
|
||||
@ -4465,7 +4463,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runLamdbaFunctions() throws ExpressionVisitException, ODataApplicationException, UriParserException {
|
||||
public void lambdaFunctions() throws Exception {
|
||||
|
||||
testFilter.runOnETKeyNav("any(d:d/PropertyInt16 eq 1)")
|
||||
.is("<<ANY;<<d/PropertyInt16> eq <1>>>>")
|
||||
@ -4612,7 +4610,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runIsOf() throws ExpressionVisitException, ODataApplicationException, UriParserException {
|
||||
public void runIsOf() throws Exception {
|
||||
|
||||
testFilter.runOnETKeyNav("isof(olingo.odata.test1.ETTwoKeyNav)")
|
||||
.is("<isof(<olingo.odata.test1.ETTwoKeyNav>)>")
|
||||
@ -4757,7 +4755,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHas() throws ExpressionVisitException, ODataApplicationException, UriParserException {
|
||||
public void has() throws Exception {
|
||||
|
||||
testFilter.runOnETMixEnumDefCollComp("PropertyEnumString has olingo.odata.test1.ENString'String1'")
|
||||
.is("<<PropertyEnumString> has <olingo.odata.test1.ENString<String1>>>")
|
||||
@ -5086,7 +5084,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderby() throws UriParserException, UnsupportedEncodingException {
|
||||
public void orderby() throws Exception {
|
||||
|
||||
testFilter.runOrderByOnETTwoKeyNav("olingo.odata.test1.UFCRTETAllPrimTwoParam("
|
||||
+ "ParameterString=@ParamStringAlias,ParameterInt16=@ParamInt16Alias)/PropertyString eq 'SomeString'")
|
||||
@ -5429,7 +5427,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
public void search() throws Exception {
|
||||
testUri.run("ESTwoKeyNav", "$search=abc");
|
||||
testUri.run("ESTwoKeyNav", "$search=NOT abc");
|
||||
|
||||
@ -5462,6 +5460,9 @@ public class TestFullResourcePath {
|
||||
testUri.run("ESTwoKeyNav", "$search=abc AND (def OR ghi)");
|
||||
testUri.run("ESTwoKeyNav", "$search=abc AND (def ghi)");
|
||||
|
||||
// search in function-import return value
|
||||
testUri.run("FICRTCollESTwoKeyNavParam(ParameterInt16=1)", "$search=test");
|
||||
|
||||
// percent encoded characters
|
||||
testUri.run("ESTwoKeyNav", "$search=%41%42%43");
|
||||
testUri.run("ESTwoKeyNav", "$search=\"100%25\"");
|
||||
@ -5484,7 +5485,6 @@ public class TestFullResourcePath {
|
||||
|
||||
/**
|
||||
* https://tools.oasis-open.org/version-control/browse/wsvn/odata/trunk/spec/ABNF/odata-abnf-testcases.xml
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void searchQueryPhraseAbnfTestcases() throws Exception {
|
||||
@ -5568,10 +5568,10 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrors() {
|
||||
public void errors() {
|
||||
testUri.runEx("FICRTString(wrong1='ABC')/olingo.odata.test1.BFCStringRTESTwoKeyNav()")
|
||||
.isExSemantic(MessageKeys.FUNCTION_NOT_FOUND);
|
||||
testUri.runEx("FICRTString(wrong1='ABC', wrong2=1)/olingo.odata.test1.BFCStringRTESTwoKeyNav()")
|
||||
testUri.runEx("FICRTString(wrong1='ABC',wrong2=1)/olingo.odata.test1.BFCStringRTESTwoKeyNav()")
|
||||
.isExSemantic(MessageKeys.FUNCTION_NOT_FOUND);
|
||||
|
||||
// type filter for entity incompatible
|
||||
@ -5620,14 +5620,14 @@ public class TestFullResourcePath {
|
||||
|
||||
// Actions must not be followed by anything.
|
||||
testUri.runEx(ContainerProvider.AIRT_STRING + "/$value")
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_VALUE);
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
testUri.runEx(ContainerProvider.AIRTCT_TWO_PRIM_PARAM + "/PropertyInt16")
|
||||
.isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/"
|
||||
+ "olingo.odata.test1.BAETTwoKeyNavRTETTwoKeyNav/olingo.odata.test1.ETTwoKeyNav")
|
||||
.isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BAESTwoKeyNavRTESTwoKeyNav/$count")
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_COUNT);
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -5646,7 +5646,7 @@ public class TestFullResourcePath {
|
||||
@Test
|
||||
public void multipleKeysInResourcePath() throws Exception {
|
||||
// See OLINGO-730
|
||||
testUri.runEx("ESAllPrim(32767)(1)(2)").isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
testUri.runEx("ESAllPrim(32767)(1)(2)").isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -5705,9 +5705,9 @@ public class TestFullResourcePath {
|
||||
|
||||
@Test
|
||||
public void navigationWithMoreThanOneKey() throws Exception {
|
||||
testUri.runEx("ESKeyNav(1)/NavPropertyETTwoKeyNavMany(PropertyInt=1,PropertyString='2')"
|
||||
+ "(PropertyInt=1,PropertyString='2')")
|
||||
.isExSemantic(MessageKeys.WRONG_NUMBER_OF_KEY_PROPERTIES);
|
||||
testUri.runEx("ESKeyNav(1)/NavPropertyETTwoKeyNavMany(PropertyInt16=1,PropertyString='2')"
|
||||
+ "(PropertyInt16=1,PropertyString='2')")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -5724,10 +5724,14 @@ public class TestFullResourcePath {
|
||||
testUri.runEx("FICRTETKeyNav()/SINav").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
|
||||
testUri.runEx("FICRTETKeyNav()/FICRTString()").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
|
||||
testUri.runEx("FICRTETKeyNav()/AIRTString").isExSemantic(MessageKeys.PROPERTY_NOT_IN_TYPE);
|
||||
testUri.runEx("AIRTESAllPrimParam/ESAllPrim(0)").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("AIRTESAllPrimParam/SINav").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("AIRTESAllPrimParam/FICRTString()").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("AIRTESAllPrimParam/AIRTString").isExSemantic(MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
testUri.runEx("AIRTESAllPrimParam/ESAllPrim(0)")
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
testUri.runEx("AIRTESAllPrimParam/SINav")
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
testUri.runEx("AIRTESAllPrimParam/FICRTString()")
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
testUri.runEx("AIRTESAllPrimParam/AIRTString")
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -5737,7 +5741,7 @@ public class TestFullResourcePath {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFirstResourcePathWithNamespace() {
|
||||
public void firstResourcePathWithNamespace() {
|
||||
testUri.runEx("olingo.odata.test1.ESAllPrim").isExSemantic(MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
|
||||
testUri.runEx("olingo.odata.test1.ESAllPrim(0)").isExSemantic(MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
|
||||
testUri.runEx("olingo.odata.test1.FINRTInt16()").isExSemantic(MessageKeys.NAMESPACE_NOT_ALLOWED_AT_FIRST_ELEMENT);
|
||||
@ -5764,7 +5768,7 @@ public class TestFullResourcePath {
|
||||
Mockito.when(entityType.getFullQualifiedName()).thenReturn(nameETNavProp);
|
||||
Mockito.when(entityType.getKeyPredicateNames()).thenReturn(Collections.singletonList(keyPropertyName));
|
||||
Mockito.when(entityType.getKeyPropertyRefs()).thenReturn(Collections.singletonList(keyPropertyRef));
|
||||
Mockito.when(entityType.getProperty(entitySetName)).thenReturn(navProperty);
|
||||
Mockito.when(entityType.getNavigationProperty(entitySetName)).thenReturn(navProperty);
|
||||
Mockito.when(navProperty.getType()).thenReturn(entityType);
|
||||
EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
|
||||
Mockito.when(entitySet.getName()).thenReturn(entitySetName);
|
||||
@ -5772,7 +5776,7 @@ public class TestFullResourcePath {
|
||||
EdmEntityContainer container = Mockito.mock(EdmEntityContainer.class);
|
||||
Mockito.when(container.getEntitySet(entitySetName)).thenReturn(entitySet);
|
||||
Edm mockedEdm = Mockito.mock(Edm.class);
|
||||
Mockito.when(mockedEdm.getEntityContainer(null)).thenReturn(container);
|
||||
Mockito.when(mockedEdm.getEntityContainer()).thenReturn(container);
|
||||
new TestUriValidator().setEdm(mockedEdm)
|
||||
.run("ESNavProp(1)/ESNavProp(2)/ESNavProp(3)/ESNavProp")
|
||||
.goPath()
|
||||
@ -5886,11 +5890,11 @@ public class TestFullResourcePath {
|
||||
@Test
|
||||
public void functionsWithComplexParameters() throws Exception {
|
||||
testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}")
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}")
|
||||
.goPath()
|
||||
.at(0).isEntitySet("ESTwoKeyNav")
|
||||
.at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
|
||||
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
|
||||
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"PropertyString\":\"1\"}");
|
||||
|
||||
// Test JSON String lexer rule =\"3,Int16=abc},\\\nabc&test%test\b\f\r\t\u0022\\}\\{\\)\\(\\]\\[}
|
||||
final String stringValueEncoded = "=\\\"3,Int16=abc},\\\\\\nabc%26test%25test\\b\\f\\r\\t\\u0022\\\\}\\\\{\\\\)"
|
||||
@ -5899,11 +5903,11 @@ public class TestFullResourcePath {
|
||||
+ "\\\\(\\\\]\\\\[}";
|
||||
|
||||
testUri.run("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueEncoded + "\"}")
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"PropertyString\":\"" + stringValueEncoded + "\"}")
|
||||
.goPath()
|
||||
.at(0).isEntitySet("ESTwoKeyNav")
|
||||
.at(1).isFunction("BFCESTwoKeyNavRTStringParam").isParameterAlias(0, "ParameterComp", "@p1")
|
||||
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"ProperyString\":\"" + stringValueDecoded + "\"}");
|
||||
.isInAliasToValueMap("@p1", "{\"PropertyInt16\":1,\"PropertyString\":\"" + stringValueDecoded + "\"}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp={\"PropertyString\":\"Test\",\"PropertyInt16\":1}) eq 'Test'")
|
||||
@ -5916,24 +5920,24 @@ public class TestFullResourcePath {
|
||||
.isParameterText(0, "{\"PropertyString\":\"" + stringValueDecoded + "\",\"PropertyInt16\":1}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}");
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":null}")
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":null}")
|
||||
.goFilter().left().isParameterText(0, null);
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3],\"ProperyString\":\"1\"}");
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3],\"PropertyString\":\"1\"}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[\"1\",\"2\",\"3\"],\"ProperyString\":\"1\"}");
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[\"1\",\"2\",\"3\"],\"PropertyString\":\"1\"}");
|
||||
|
||||
testUri.run("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[{\"Prop1\":123,\"Prop2\":\"Test\",\"Prop3\":[1,2,3]},"
|
||||
+ "{\"Prop1\":{\"Prop1\":[\"Prop\\\":{]\"]}}],\"ProperyString\":\"1\"}");
|
||||
+ "{\"Prop1\":{\"Prop1\":[\"Prop\\\":{]\"]}}],\"PropertyString\":\"1\"}");
|
||||
|
||||
testUri.run("FINRTByteNineParam(ParameterEnum=null,ParameterDef='x',ParameterComp=@c,"
|
||||
+ "ParameterETTwoPrim=@c,CollParameterByte=@e,CollParameterEnum=@e,CollParameterDef=@e,"
|
||||
@ -5941,12 +5945,12 @@ public class TestFullResourcePath {
|
||||
"@c={}&@e=[]");
|
||||
|
||||
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"ProperyString\":'1'}")
|
||||
+ "(ParameterComp=@p1)", "@p1={\"PropertyInt16\":1,\"PropertyString\":'1'}")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp={\"PropertyInt16\":1,\"PropertyString\":\"Test\"})")
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.COMPLEX_PARAMETER_IN_RESOURCE_PATH);
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
|
||||
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=null)")
|
||||
.isExValidation(UriValidationException.MessageKeys.MISSING_PARAMETER);
|
||||
@ -5959,7 +5963,7 @@ public class TestFullResourcePath {
|
||||
|
||||
testUri.run("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
|
||||
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test, UnknownParam=1)", "@test='null'")
|
||||
testUri.runEx("FICRTCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test,UnknownParam=1)", "@test='null'")
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND);
|
||||
|
||||
testUri.run("FICRTCollCTTwoPrimTwoParam(ParameterInt16=1,ParameterString=@test)", "@test='null'");
|
||||
@ -5974,23 +5978,23 @@ public class TestFullResourcePath {
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.FUNCTION_IMPORT_NOT_ALLOWED);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"")
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"ProperyString\":\"1\"}}")
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":1,\"PropertyString\":\"1\"}}")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3]],\"ProperyString\":\"1\"}")
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3]],\"PropertyString\":\"1\"}")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3,\"ProperyString\":\"1\"}")
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3,\"PropertyString\":\"1\"}")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
|
||||
testUri.runEx("ESTwoKeyNav", "$filter=olingo.odata.test1.BFCESTwoKeyNavRTStringParam"
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3},\"ProperyString\":\"1\"}")
|
||||
+ "(ParameterComp=@p1) eq 0&@p1={\"PropertyInt16\":[1,2,3},\"PropertyString\":\"1\"}")
|
||||
.isExSyntax(UriParserSyntaxException.MessageKeys.SYNTAX);
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ import org.apache.olingo.server.api.edmx.EdmxReference;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriResourceKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
|
||||
import org.apache.olingo.server.core.uri.testutil.FilterValidator;
|
||||
@ -186,11 +185,11 @@ public class TestUriParserImpl {
|
||||
.isType(EntityTypeProvider.nameETTwoKeyTwoPrim, false);
|
||||
|
||||
testUri.runEx(ContainerProvider.AIRT_STRING + "/invalidElement")
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS);
|
||||
.isExValidation(UriValidationException.MessageKeys.UNALLOWED_RESOURCE_PATH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runCount() {
|
||||
public void count() {
|
||||
|
||||
// count entity set
|
||||
testRes.run("ESAllPrim/$count")
|
||||
@ -338,7 +337,7 @@ public class TestUriParserImpl {
|
||||
.isKeyPredicate(0, "PropertyInt16", "1");
|
||||
|
||||
// with two keys
|
||||
testRes.run("ESTwoKeyTwoPrim(PropertyInt16=1, PropertyString='ABC')")
|
||||
testRes.run("ESTwoKeyTwoPrim(PropertyInt16=1,PropertyString='ABC')")
|
||||
.isEntitySet("ESTwoKeyTwoPrim")
|
||||
.isKeyPredicate(0, "PropertyInt16", "1")
|
||||
.isKeyPredicate(1, "PropertyString", "'ABC'");
|
||||
@ -562,14 +561,14 @@ public class TestUriParserImpl {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnary() throws UriParserException {
|
||||
public void unary() throws Exception {
|
||||
testFilter.runOnETAllPrim("not PropertyBoolean").isCompr("<not <PropertyBoolean>>");
|
||||
testFilter.runOnETAllPrim("- PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
|
||||
testFilter.runOnETAllPrim("-PropertyInt16 eq PropertyInt16").isCompr("<<- <PropertyInt16>> eq <PropertyInt16>>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterComplexMixedPriority() throws UriParserException {
|
||||
public void filterComplexMixedPriority() throws Exception {
|
||||
testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64")
|
||||
.isCompr("<<PropertyInt16> or <<PropertyInt32> and <PropertyInt64>>>");
|
||||
testFilter.runOnETAllPrim("PropertyInt16 or PropertyInt32 and PropertyInt64 eq PropertyByte")
|
||||
@ -594,7 +593,7 @@ public class TestUriParserImpl {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFilterSimpleSameBinaryBinaryBinaryPriority() throws UriParserException {
|
||||
public void filterSimpleSameBinaryBinaryBinaryPriority() throws Exception {
|
||||
testFilter.runOnETAllPrim("1 add 2 add 3 add 4").isCompr("<<< <1> add <2>> add <3>> add <4>>");
|
||||
testFilter.runOnETAllPrim("1 add 2 add 3 div 4").isCompr("<< <1> add <2>> add <<3> div <4>>>");
|
||||
testFilter.runOnETAllPrim("1 add 2 div 3 add 4").isCompr("<< <1> add <<2> div <3>>> add <4>>");
|
||||
@ -1101,7 +1100,7 @@ public class TestUriParserImpl {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGeo() throws UriParserException {
|
||||
public void geo() throws Exception {
|
||||
testFilter.runOnETAllPrim("geo.distance(PropertySByte,PropertySByte)")
|
||||
.is("<geo.distance(<PropertySByte>,<PropertySByte>)>")
|
||||
.isMethod(MethodKind.GEODISTANCE, 2);
|
||||
|
@ -55,7 +55,7 @@ public class ParserTest {
|
||||
EdmEntityType productsType = Mockito.mock(EdmEntityType.class);
|
||||
|
||||
final FullQualifiedName nameProducts = new FullQualifiedName("NS", "Products");
|
||||
Mockito.when(mockEdm.getEntityContainer(null)).thenReturn(container);
|
||||
Mockito.when(mockEdm.getEntityContainer()).thenReturn(container);
|
||||
Mockito.when(typeCategory.getName()).thenReturn("Category");
|
||||
Mockito.when(typeCategory.getNamespace()).thenReturn("NS");
|
||||
Mockito.when(esCategory.getEntityType()).thenReturn(typeCategory);
|
||||
@ -97,7 +97,7 @@ public class ParserTest {
|
||||
EdmEntityType typeProduct = Mockito.mock(EdmEntityType.class);
|
||||
FullQualifiedName fqnProduct = new FullQualifiedName("NS", "Products");
|
||||
|
||||
Mockito.when(mockEdm.getEntityContainer(null)).thenReturn(container);
|
||||
Mockito.when(mockEdm.getEntityContainer()).thenReturn(container);
|
||||
Mockito.when(typeCategory.getName()).thenReturn(fqnCategory.getName());
|
||||
Mockito.when(typeCategory.getNamespace()).thenReturn(fqnCategory.getNamespace());
|
||||
Mockito.when(typeCategory.getFullQualifiedName()).thenReturn(fqnCategory);
|
||||
|
@ -28,7 +28,9 @@ import java.util.List;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
@ -51,8 +53,10 @@ import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
|
||||
import org.apache.olingo.server.core.uri.queryoption.expression.MemberImpl;
|
||||
import org.apache.olingo.server.core.uri.queryoption.expression.MethodImpl;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
|
||||
public class FilterValidator implements TestValidator {
|
||||
private final OData odata = OData.newInstance();
|
||||
private Edm edm;
|
||||
|
||||
private TestValidator invokedByValidator;
|
||||
@ -62,7 +66,7 @@ public class FilterValidator implements TestValidator {
|
||||
private Expression curExpression;
|
||||
private Expression rootExpression;
|
||||
|
||||
private UriParserException exception;
|
||||
private ODataLibraryException exception;
|
||||
|
||||
// --- Setup ---
|
||||
public FilterValidator setUriResourcePathValidator(final ResourceValidator uriResourcePathValidator) {
|
||||
@ -107,15 +111,18 @@ public class FilterValidator implements TestValidator {
|
||||
|
||||
// --- Execution ---
|
||||
|
||||
public FilterValidator runOrderByOnETAllPrim(final String orderBy) throws UriParserException {
|
||||
public FilterValidator runOrderByOnETAllPrim(final String orderBy)
|
||||
throws UriParserException, UriValidationException {
|
||||
return runUriOrderBy("ESAllPrim", "$orderby=" + orderBy.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOrderByOnETTwoKeyNav(final String orderBy) throws UriParserException {
|
||||
public FilterValidator runOrderByOnETTwoKeyNav(final String orderBy)
|
||||
throws UriParserException, UriValidationException {
|
||||
return runUriOrderBy("ESTwoKeyNav", "$orderby=" + orderBy.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOrderByOnETMixEnumDefCollComp(final String orderBy) throws UriParserException {
|
||||
public FilterValidator runOrderByOnETMixEnumDefCollComp(final String orderBy)
|
||||
throws UriParserException, UriValidationException {
|
||||
return runUriOrderBy("ESMixEnumDefCollComp", "$orderby=" + orderBy.trim());
|
||||
}
|
||||
|
||||
@ -123,15 +130,17 @@ public class FilterValidator implements TestValidator {
|
||||
return runUriOrderByEx("ESTwoKeyNav", "$orderby=" + orderBy.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnETTwoKeyNav(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnETTwoKeyNav(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESTwoKeyNav", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnETMixEnumDefCollComp(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnETMixEnumDefCollComp(final String filter)
|
||||
throws UriParserException, UriValidationException {
|
||||
return runUri("ESMixEnumDefCollComp", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnETTwoKeyNavSingle(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnETTwoKeyNavSingle(final String filter)
|
||||
throws UriParserException, UriValidationException {
|
||||
return runUri("SINav", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
@ -139,11 +148,11 @@ public class FilterValidator implements TestValidator {
|
||||
return runUriEx("ESTwoKeyNav", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnETAllPrim(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnETAllPrim(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESAllPrim(1)", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnETKeyNav(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnETKeyNav(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESKeyNav(1)", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
@ -151,35 +160,36 @@ public class FilterValidator implements TestValidator {
|
||||
return runUriEx("ESKeyNav(1)", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnCTTwoPrim(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnCTTwoPrim(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("SINav/PropertyCompTwoPrim", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnString(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnString(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("SINav/PropertyString", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnInt32(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnInt32(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESCollAllPrim(1)/CollPropertyInt32", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnDateTimeOffset(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnDateTimeOffset(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESCollAllPrim(1)/CollPropertyDateTimeOffset", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnDuration(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnDuration(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESCollAllPrim(1)/CollPropertyDuration", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runOnTimeOfDay(final String filter) throws UriParserException {
|
||||
public FilterValidator runOnTimeOfDay(final String filter) throws UriParserException, UriValidationException {
|
||||
return runUri("ESCollAllPrim(1)/CollPropertyTimeOfDay", "$filter=" + filter.trim());
|
||||
}
|
||||
|
||||
public FilterValidator runUri(final String path, final String query) throws UriParserException {
|
||||
Parser parser = new Parser();
|
||||
public FilterValidator runUri(final String path, final String query)
|
||||
throws UriParserException, UriValidationException {
|
||||
Parser parser = new Parser(edm, odata);
|
||||
UriInfo uriInfo = null;
|
||||
|
||||
uriInfo = parser.parseUri(path, query, null, edm);
|
||||
uriInfo = parser.parseUri(path, query, null);
|
||||
|
||||
if (uriInfo.getKind() != UriInfoKind.resource) {
|
||||
fail("Filtervalidator can only be used on resourcePaths");
|
||||
@ -193,19 +203,19 @@ public class FilterValidator implements TestValidator {
|
||||
public FilterValidator runUriEx(final String path, final String query) {
|
||||
exception = null;
|
||||
try {
|
||||
new Parser().parseUri(path, query, null, edm);
|
||||
new Parser(edm, odata).parseUri(path, query, null);
|
||||
fail("Expected exception not thrown.");
|
||||
} catch (final UriParserException e) {
|
||||
exception = e;
|
||||
} catch (final UriValidationException e) {
|
||||
exception = e;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public FilterValidator runUriOrderBy(final String path, final String query) throws UriParserException {
|
||||
Parser parser = new Parser();
|
||||
UriInfo uriInfo = null;
|
||||
|
||||
uriInfo = parser.parseUri(path, query, null, edm);
|
||||
public FilterValidator runUriOrderBy(final String path, final String query)
|
||||
throws UriParserException, UriValidationException {
|
||||
final UriInfo uriInfo = new Parser(edm, odata).parseUri(path, query, null);
|
||||
|
||||
if (uriInfo.getKind() != UriInfoKind.resource) {
|
||||
fail("Filtervalidator can only be used on resourcePaths");
|
||||
@ -218,10 +228,12 @@ public class FilterValidator implements TestValidator {
|
||||
public FilterValidator runUriOrderByEx(final String path, final String query) {
|
||||
exception = null;
|
||||
try {
|
||||
new Parser().parseUri(path, query, null, edm);
|
||||
new Parser(edm, odata).parseUri(path, query, null);
|
||||
fail("Expected exception not thrown.");
|
||||
} catch (final UriParserException e) {
|
||||
exception = e;
|
||||
} catch (final UriValidationException e) {
|
||||
exception = e;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -20,6 +20,8 @@ package org.apache.olingo.server.core.uri.testutil;
|
||||
|
||||
import org.antlr.v4.runtime.DefaultErrorStrategy;
|
||||
import org.antlr.v4.runtime.DiagnosticErrorListener;
|
||||
import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.core.uri.antlr.UriParserParser;
|
||||
import org.apache.olingo.server.core.uri.parser.Parser;
|
||||
|
||||
@ -27,7 +29,8 @@ public class ParserWithLogging extends Parser {
|
||||
TestErrorLogger errorCollector1;
|
||||
TestErrorLogger errorCollector2;
|
||||
|
||||
public ParserWithLogging() {
|
||||
public ParserWithLogging(final Edm edm, final OData odata) {
|
||||
super(edm, odata);
|
||||
errorCollector1 = new TestErrorLogger("Stage 1", 1);
|
||||
errorCollector2 = new TestErrorLogger("Stage 2", 1);
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ import org.apache.olingo.commons.api.edm.EdmElement;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
@ -50,11 +52,11 @@ import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectItem;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl;
|
||||
import org.apache.olingo.server.core.uri.parser.UriParserException;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidator;
|
||||
|
||||
public class ResourceValidator implements TestValidator {
|
||||
private final OData odata = OData.newInstance();
|
||||
private Edm edm;
|
||||
private TestValidator invokedBy;
|
||||
private UriInfo uriInfo = null;
|
||||
@ -83,13 +85,13 @@ public class ResourceValidator implements TestValidator {
|
||||
// --- Execution ---
|
||||
|
||||
public ResourceValidator run(final String path) {
|
||||
ParserWithLogging testParser = new ParserWithLogging();
|
||||
ParserWithLogging testParser = new ParserWithLogging(edm, odata);
|
||||
|
||||
UriInfo uriInfoTmp = null;
|
||||
uriPathInfo = null;
|
||||
try {
|
||||
uriInfoTmp = testParser.parseUri(path, null, null, edm);
|
||||
} catch (final UriParserException e) {
|
||||
uriInfoTmp = testParser.parseUri(path, null, null);
|
||||
} catch (final ODataLibraryException e) {
|
||||
fail("Exception occurred while parsing the URI: " + path + "\n"
|
||||
+ " Message: " + e.getMessage());
|
||||
}
|
||||
@ -279,7 +281,8 @@ public class ResourceValidator implements TestValidator {
|
||||
|
||||
// input parameter type may be null in order to assert that the collectionTypeFilter is not set
|
||||
EdmType actualType = uriPathInfoKeyPred.getTypeFilterOnCollection();
|
||||
assertEquals(expectedType, expectedType == null ? actualType : actualType.getFullQualifiedName());
|
||||
assertEquals(expectedType,
|
||||
expectedType == null || actualType == null ? actualType : actualType.getFullQualifiedName());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import org.apache.olingo.commons.api.edm.Edm;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.server.api.OData;
|
||||
import org.apache.olingo.server.api.ODataLibraryException;
|
||||
import org.apache.olingo.server.api.uri.UriInfo;
|
||||
import org.apache.olingo.server.api.uri.UriInfoKind;
|
||||
@ -44,6 +45,7 @@ import org.apache.olingo.server.core.uri.validator.UriValidationException;
|
||||
import org.apache.olingo.server.core.uri.validator.UriValidator;
|
||||
|
||||
public class TestUriValidator implements TestValidator {
|
||||
private final OData odata = OData.newInstance();
|
||||
private Edm edm;
|
||||
|
||||
private UriInfo uriInfo;
|
||||
@ -62,17 +64,14 @@ public class TestUriValidator implements TestValidator {
|
||||
|
||||
public TestUriValidator run(final String path, final String query)
|
||||
throws UriParserException, UriValidationException {
|
||||
Parser parser = new Parser();
|
||||
UriValidator validator = new UriValidator();
|
||||
|
||||
uriInfo = parser.parseUri(path, query, null, edm);
|
||||
validator.validate(uriInfo, HttpMethod.GET);
|
||||
uriInfo = new Parser(edm, odata).parseUri(path, query, null);
|
||||
new UriValidator().validate(uriInfo, HttpMethod.GET);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TestUriValidator run(final String path, final String query, final String fragment)
|
||||
throws UriParserException, UriValidationException {
|
||||
uriInfo = new Parser().parseUri(path, query, fragment, edm);
|
||||
uriInfo = new Parser(edm, odata).parseUri(path, query, fragment);
|
||||
new UriValidator().validate(uriInfo, HttpMethod.GET);
|
||||
return this;
|
||||
}
|
||||
@ -82,10 +81,9 @@ public class TestUriValidator implements TestValidator {
|
||||
}
|
||||
|
||||
public TestUriValidator runEx(final String path, final String query) {
|
||||
Parser parser = new Parser();
|
||||
uriInfo = null;
|
||||
try {
|
||||
uriInfo = parser.parseUri(path, query, null, edm);
|
||||
uriInfo = new Parser(edm, odata).parseUri(path, query, null);
|
||||
new UriValidator().validate(uriInfo, HttpMethod.GET);
|
||||
fail("Exception expected");
|
||||
} catch (UriParserException e) {
|
||||
|
@ -323,7 +323,8 @@ public class UriValidatorTest {
|
||||
{ URI_ACTION_ES, QO_ID }
|
||||
};
|
||||
|
||||
private static final Edm edm = OData.newInstance().createServiceMetadata(
|
||||
private static final OData odata = OData.newInstance();
|
||||
private static final Edm edm = odata.createServiceMetadata(
|
||||
new EdmTechProvider(), Collections.<EdmxReference> emptyList()).getEdm();
|
||||
|
||||
@Test
|
||||
@ -419,24 +420,24 @@ public class UriValidatorTest {
|
||||
public void checkKeys() throws Exception {
|
||||
final TestUriValidator testUri = new TestUriValidator().setEdm(edm);
|
||||
|
||||
testUri.run("ESTwoKeyNav(PropertyInt16=1, PropertyString='abc')");
|
||||
testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='abc')");
|
||||
|
||||
testUri.runEx("ESTwoKeyNav(xxx=1, yyy='abc')")
|
||||
testUri.runEx("ESTwoKeyNav(xxx=1,yyy='abc')")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
testUri.runEx("ESCollAllPrim(null)").isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
testUri.runEx("ESAllPrim(PropertyInt16='1')")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESAllPrim(12345678901234567890)")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString=1)")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
|
||||
testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyInt16=1)")
|
||||
.isExValidation(UriValidationException.MessageKeys.DOUBLE_KEY_PROPERTY);
|
||||
|
||||
testUri.runEx("ESAllPrim(0)/NavPropertyETTwoPrimMany(xxx=42)")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
testUri.runEx("ESAllPrim(0)/NavPropertyETTwoPrimMany(PropertyInt16='1')")
|
||||
.isExValidation(UriValidationException.MessageKeys.INVALID_KEY_PROPERTY);
|
||||
.isExSemantic(UriParserSemanticException.MessageKeys.INVALID_KEY_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -499,7 +500,7 @@ public class UriValidatorTest {
|
||||
|
||||
private void validate(final String path, final String query, final HttpMethod method) {
|
||||
try {
|
||||
new UriValidator().validate(new Parser().parseUri(path, query, null, edm), method);
|
||||
new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null), method);
|
||||
} catch (final UriParserException e) {
|
||||
fail("Failed for uri: " + path + '?' + query);
|
||||
} catch (final UriValidationException e) {
|
||||
@ -510,7 +511,7 @@ public class UriValidatorTest {
|
||||
private void validateWrong(final String path, final String query, final HttpMethod method,
|
||||
final UriValidationException.MessageKeys expectedMessageKey) {
|
||||
try {
|
||||
new UriValidator().validate(new Parser().parseUri(path, query, null, edm), method);
|
||||
new UriValidator().validate(new Parser(edm, odata).parseUri(path, query, null), method);
|
||||
fail("Validation Exception not thrown: " + method + ' ' + path + '?' + query);
|
||||
} catch (final UriParserException e) {
|
||||
fail("Wrong Exception thrown: " + method + ' ' + path + '?' + query);
|
||||
|
Loading…
x
Reference in New Issue
Block a user