[OLINGO-545] OrderBy and Filter System Query Option evaluation added to TecScenario
Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
parent
cfb72decd1
commit
0e6c9a1183
|
@ -18,6 +18,15 @@
|
|||
*/
|
||||
package org.apache.olingo.fit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.olingo.client.api.CommonODataClient;
|
||||
|
@ -34,15 +43,6 @@ import org.junit.BeforeClass;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.StringWriter;
|
||||
|
||||
public abstract class AbstractBaseTestITCase {
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
*/
|
||||
package org.apache.olingo.fit;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
|
||||
|
@ -50,6 +50,9 @@ import org.apache.olingo.client.core.http.AbstractOAuth2HttpClientFactory;
|
|||
import org.apache.olingo.client.core.http.OAuth2Exception;
|
||||
import org.apache.olingo.fit.rest.OAuth2Provider;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
|
||||
|
||||
public class CXFOAuth2HttpClientFactory extends AbstractOAuth2HttpClientFactory {
|
||||
|
||||
private static final OAuthClientUtils.Consumer OAUTH2_CONSUMER =
|
||||
|
|
|
@ -0,0 +1,976 @@
|
|||
/*
|
||||
* 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.fit.tecsvc.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.olingo.client.api.ODataClient;
|
||||
import org.apache.olingo.client.api.communication.ODataClientErrorException;
|
||||
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
|
||||
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
|
||||
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
|
||||
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
|
||||
import org.apache.olingo.client.core.ODataClientFactory;
|
||||
import org.apache.olingo.commons.api.domain.ODataEntity;
|
||||
import org.apache.olingo.commons.api.domain.ODataEntitySet;
|
||||
import org.apache.olingo.commons.api.domain.ODataObjectFactory;
|
||||
import org.apache.olingo.commons.api.domain.ODataValuable;
|
||||
import org.apache.olingo.commons.api.edm.FullQualifiedName;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.fit.AbstractBaseTestITCase;
|
||||
import org.apache.olingo.fit.tecsvc.TecSvcConst;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FilterSystemQueryITCase extends AbstractBaseTestITCase {
|
||||
|
||||
private static final String ES_COMP_ALL_PRIM = "ESCompAllPrim";
|
||||
private static final String SERVICE_URI = TecSvcConst.BASE_URI;
|
||||
private static final String ES_TWO_KEY_NAV = "ESTwoKeyNav";
|
||||
private static final String ES_ALL_PRIM = "ESAllPrim";
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownAfterClass() throws Exception {}
|
||||
|
||||
@Test
|
||||
public void testTimeOfDayLiteral() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "PropertyTimeOfDay eq 03:26:05");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateLiteral() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "PropertyDate eq 2012-12-03");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeOffsetLiteral() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-03T07:16:23Z");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInt64Literal() {
|
||||
long value = Integer.MAX_VALUE + 1L;
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyInt64 gt " + value);
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleLiteral() {
|
||||
Double value = -17900000000000000000.0;
|
||||
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDouble le " + value.toString());
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleEq() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq 1");
|
||||
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryIntegerOperations() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 add 1 eq (1 sub 3) div 2 mul 3 add 7");
|
||||
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientEscaping() {
|
||||
final ODataClient client = getClient();
|
||||
final String filter = client.getFilterFactory().eq(
|
||||
client.getFilterFactory().getArgFactory().property("PropertyString"),
|
||||
client.getFilterFactory().getArgFactory().literal("First Resource - positive values")).build();
|
||||
|
||||
final URI uri = client.newURIBuilder(SERVICE_URI)
|
||||
.appendEntitySetSegment(ES_ALL_PRIM)
|
||||
.filter(filter)
|
||||
.build();
|
||||
|
||||
final ODataRetrieveResponse<ODataEntitySet> response = client.getRetrieveRequestFactory()
|
||||
.getEntitySetRequest(uri).execute();
|
||||
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringProperty() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyString eq '2'");
|
||||
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanOperator() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_TWO_KEY_NAV, "PropertyString eq '2' and PropertyInt16 eq 1");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyString eq '2' or PropertyInt16 eq 1");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanOperatorWithNull() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq null");
|
||||
assertEquals(0, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "null eq null");
|
||||
assertEquals(4, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "null ne null");
|
||||
assertEquals(0, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnaryWithNullLiterals() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyBoolean eq not null");
|
||||
assertEquals(0, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyComp/PropertyComp/PropertyBoolean eq 0 add -(5 add null)");
|
||||
assertEquals(0, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnaryWithWrongTypes() {
|
||||
fail(ES_ALL_PRIM, "PropertyInt16 eq 6 add - 'test'", HttpStatusCode.BAD_REQUEST);
|
||||
fail(ES_ALL_PRIM, "PropertyBoolean eq not 'test'", HttpStatusCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodCallsWithNull() {
|
||||
// One representative of "stringFuntion" "residue class"
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "endswith(PropertyString, null) eq null"); // null eq null => true
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
// One representative of "stringifiedValueFunction" "residue class"
|
||||
result = sendRequest(ES_ALL_PRIM, "substring(PropertyString, null) eq null"); // null eq null => true
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
// Substring
|
||||
result = sendRequest(ES_ALL_PRIM, "hour(null) eq null"); // null eq null => true
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_ALL_PRIM, "substring(PropertyString, 0, null) eq null"); // null eq null => true
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnknownLiteral() {
|
||||
// Check if the error code is equals to 400
|
||||
fail(ES_ALL_PRIM, "PropertyInt16 eq ThisIsNotAValidLiteral", HttpStatusCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorCodeArithmetic() {
|
||||
fail(ES_ALL_PRIM, "PropertyInt16 eq 'hey' add 5", HttpStatusCode.BAD_REQUEST);
|
||||
fail(ES_ALL_PRIM, "PropertyDate eq 5.0 add 2012-12-03", HttpStatusCode.BAD_REQUEST);
|
||||
fail(ES_ALL_PRIM, "PropertyDouble mod 5 eq 0", HttpStatusCode.BAD_REQUEST);
|
||||
fail(ES_ALL_PRIM, "UnkownProperty eq null", HttpStatusCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericBinaryOperationWithNullValues() {
|
||||
// Create new Entries
|
||||
final String filterString = "PropertyString eq null";
|
||||
|
||||
ODataClient client = getClient();
|
||||
ODataObjectFactory objectFactory = client.getObjectFactory();
|
||||
|
||||
ODataEntity entity = objectFactory.newEntity(new FullQualifiedName("olingo.odata.test1.ETAllPrim"));
|
||||
|
||||
entity.getProperties().add(
|
||||
objectFactory.newPrimitiveProperty("PropertyInt16", objectFactory.newPrimitiveValueBuilder()
|
||||
.buildInt16((short) 1)));
|
||||
|
||||
final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").build();
|
||||
ODataEntityCreateResponse<ODataEntity> createResponse =
|
||||
client.getCUDRequestFactory().getEntityCreateRequest(uri, entity).execute();
|
||||
|
||||
final URI receiveURI =
|
||||
client.newURIBuilder(SERVICE_URI)
|
||||
.appendEntitySetSegment("ESAllPrim")
|
||||
.filter(filterString)
|
||||
.build();
|
||||
|
||||
ODataEntitySetRequest<ODataEntitySet> filterRequest =
|
||||
client.getRetrieveRequestFactory().getEntitySetRequest(receiveURI);
|
||||
filterRequest.addCustomHeader(HttpHeader.COOKIE, createResponse.getHeader(HttpHeader.SET_COOKIE).iterator().next());
|
||||
ODataRetrieveResponse<ODataEntitySet> filterResponse = filterRequest.execute();
|
||||
|
||||
assertEquals(1, filterResponse.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericComparisionOperators() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 ge 1");
|
||||
assertEquals(4, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt 1");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 lt 2");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 le 2");
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_ALL_PRIM, "PropertyDouble ge -179000");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_ALL_PRIM, "PropertyDouble gt -179000");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_ALL_PRIM, "PropertyDouble lt -179000");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
result = sendRequest(ES_ALL_PRIM, "PropertyDouble le -179000");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBinaryOperationIntegerDecimalWithPromotion() {
|
||||
String filterString = ""
|
||||
+ "PropertyInt16 mod 2 eq " // Choose mod 2 == 1 => { 1, 3, .. }
|
||||
+ "(((5 sub 1) div 5) " // Integer Division 4 / 5 == 0
|
||||
+ "add 1) " // 0 + 1 = 1
|
||||
+ "and "
|
||||
+ "PropertyComp/PropertyInt16 eq " // Complex Property
|
||||
+ "5.5 mul 2"; // Single * Int16 => Single => Int16 eq Single => Single eq Single
|
||||
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, filterString);
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
assertEquals("11", ((ODataValuable) ((ODataValuable) oDataEntity.getProperty("PropertyComp")).getComplexValue()
|
||||
.get("PropertyInt16")).getValue()
|
||||
.toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
assertEquals("11", ((ODataValuable) ((ODataValuable) oDataEntity.getProperty("PropertyComp")).getComplexValue()
|
||||
.get("PropertyInt16")).getValue()
|
||||
.toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(2);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
assertEquals("11", ((ODataValuable) ((ODataValuable) oDataEntity.getProperty("PropertyComp")).getComplexValue()
|
||||
.get("PropertyInt16")).getValue()
|
||||
.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNotOperator() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "not (PropertyInt16 eq 1)");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnaryMinusOperator() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2 add - -3");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnaryMinusOperatorDecimal() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 gt -2.0 add - -3.0");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringPropertyEqualsNull() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyString eq null");
|
||||
assertEquals(0, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNullLiteral() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 add null eq 1");
|
||||
assertEquals(0, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddNullLiteralEqualsNull() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 add null eq null");
|
||||
assertEquals(4, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubstringStartAndEndGiven() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "substring(PropertyString, length('First') add 1, 8) eq ('Resource')");
|
||||
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubstringStartGiven() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_TWO_KEY_NAV, "substring(PropertyComp/PropertyComp/PropertyString, 6) eq 'Value'");
|
||||
|
||||
assertEquals(4, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(2);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(3);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unused")
|
||||
public void testSubstringDouble() {
|
||||
try {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "substring(PropertyString, length('First')"
|
||||
+ "add 1, 2.0 * 4) eq ('Resource')");
|
||||
} catch (ODataClientErrorException e) {
|
||||
assertEquals(400, e.getStatusLine().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testYearFunctionDate() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "year(PropertyDate) eq 2015");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testYearFunctionDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "year(PropertyDateTimeOffset) eq 2012");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonthFunctionDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "month(PropertyDateTimeOffset) eq 12");
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(2);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMonthFunctionDate() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "month(PropertyDate) eq 11");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDayFunctionDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "day(PropertyDateTimeOffset) eq 3");
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(2);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDayFunctionDate() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "day(PropertyDate) eq 5");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHourFunctionDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "hour(PropertyDateTimeOffset) eq 7");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHourFuntionTimeOfDay() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "hour(PropertyTimeOfDay) eq 3");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinuteFunctionDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "minute(PropertyDateTimeOffset) eq 17");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMinuteFuntionTimeOfDay() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "minute(PropertyTimeOfDay) eq 49");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecondFunctionDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "second(PropertyDateTimeOffset) eq 8");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSecondFuntionTimeOfDay() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "second(PropertyTimeOfDay) eq 14");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFractionalsecondsDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_COMP_ALL_PRIM, "fractionalseconds(PropertyComp/PropertyDateTimeOffset) eq 0.1234567");
|
||||
assertEquals(2, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(1);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFractionalsecondsDateOfTime() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "fractionalseconds(PropertyTimeOfDay) eq 0");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeFunctionsNull() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response;
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "year(null) eq null");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "month(null) eq null");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "day(null) eq null");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "hour(null) eq null");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "minute(null) eq null");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "second(null) eq null");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFloor() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq floor(3.8)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq floor(3.1)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCeiling() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq ceiling(2.1)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq ceiling(2.6)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRound() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(2.5)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(2.4)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("2", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(2.6)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
|
||||
result = sendRequest(ES_TWO_KEY_NAV, "PropertyInt16 eq round(3.1)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("3", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
assertEquals("1", ((ODataValuable) oDataEntity.getProperty("PropertyString")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEndsWith() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "endswith(PropertyString, 'values')");
|
||||
assertEquals(2, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = result.getBody().getEntities().get(1);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexOf() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "indexof(PropertyString, 'positive') eq 17");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartsWith() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result = sendRequest(ES_ALL_PRIM, "startswith(PropertyString, 'First')");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToLower() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "contains(PropertyString, tolower('POSITIVE'))");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToUpper() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "contains(PropertyString, concat(toupper('f'), 'irst'))");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTrim() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "trim(substring(PropertyString, 0, 6)) eq 'First'");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDecimalDiv() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDouble eq 0 sub (358000 div 2)");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericPromotionToInt64() {
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyInt64 eq 0");
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = result.getBody().getEntities().get(0);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void castEdm64ToDouble() {
|
||||
double value = Float.MAX_VALUE + 1;
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyInt64 lt " + value);
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeOffsetAddDuraton() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-03T07:16:19Z add duration'PT4S'");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDurrationAddDuration() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDuration eq duration'PT2S' add duration'PT4S'");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDurrationLiteral() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDuration eq duration'P1DT'");
|
||||
assertEquals(0, response.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateAddDuration() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-02 add duration'P1DT7H16M23S'");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeOffsetSubDuration() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-03T07:16:27Z sub duration'PT4S'");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDurrationSubDuration() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDuration sub duration'PT2S' eq duration'PT4S'");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateSubDuration() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDateTimeOffset eq 2012-12-04 sub duration'P0DT16H43M37S'");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateSubDate() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDuration eq 2012-12-04 sub 2012-12-04");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDateTimeOffsetSubDateTimeOffset() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response =
|
||||
sendRequest(ES_ALL_PRIM, "PropertyDuration eq 2005-12-03T00:00:00Z sub 2005-12-03T00:00:00Z");
|
||||
assertEquals(1, response.getBody().getEntities().size());
|
||||
|
||||
final ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericPromotion() {
|
||||
/*
|
||||
* The idea is use the largest possible number of a specific type and add a another number to force an
|
||||
* implicit conversion to an higher type
|
||||
*/
|
||||
ODataRetrieveResponse<ODataEntitySet> response;
|
||||
|
||||
// SByte => Int16
|
||||
byte byteValue = Byte.MAX_VALUE; // 2 ^ 7 -1 = 127
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + byteValue + " add " + 1);
|
||||
assertEquals(0, response.getBody().getEntities().size()); // No error occurs
|
||||
|
||||
// Int16 => Int32
|
||||
short shortValue = Short.MAX_VALUE;
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + shortValue + " add " + 1);
|
||||
assertEquals(0, response.getBody().getEntities().size()); // No error occurs
|
||||
|
||||
// Int32 => Int64
|
||||
int intValue = Integer.MAX_VALUE;
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + intValue + " add " + 1);
|
||||
assertEquals(0, response.getBody().getEntities().size()); // No error occurs
|
||||
|
||||
// Int64 => Double
|
||||
Long longValue = Long.MAX_VALUE;
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + longValue + " add " + 1);
|
||||
assertEquals(0, response.getBody().getEntities().size()); // No error occurs
|
||||
|
||||
// Single => Double
|
||||
Float floatValue = Float.MAX_VALUE;
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyInt32 eq " + floatValue.toString() + " add " + 1.0);
|
||||
assertEquals(0, response.getBody().getEntities().size()); // No error occurs
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullComplexProperty() {
|
||||
// Create a new entry.The complex property PropertyCompComp is set to null. So the structure of the property
|
||||
// is still there, but filled is null value (primitive types)
|
||||
// We define a filter, which returns all entry where PropertyCompComp/PropertyComp/PropertyInt16 is equals to 1
|
||||
|
||||
final ODataClient client = getClient();
|
||||
final ODataObjectFactory factory = client.getObjectFactory();
|
||||
ODataEntity newEntity = factory.newEntity(new FullQualifiedName("olingo.odata.test1", "ETKeyNav"));
|
||||
newEntity.getProperties().add(factory.newComplexProperty("PropertyCompComp", null));
|
||||
newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyInt16",
|
||||
factory.newPrimitiveValueBuilder().buildInt16((short) 4)));
|
||||
newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyString",
|
||||
factory.newPrimitiveValueBuilder().buildString("Test")));
|
||||
newEntity.getProperties().add(
|
||||
factory.newComplexProperty("PropertyCompAllPrim",
|
||||
factory.newComplexValue("CTAllPrim")
|
||||
.add(factory.newPrimitiveProperty(
|
||||
"PropertyString",
|
||||
factory.newPrimitiveValueBuilder().buildString("Test 3")))));
|
||||
|
||||
newEntity.getProperties().add(
|
||||
factory.newComplexProperty("PropertyCompTwoPrim",
|
||||
factory.newComplexValue("CTTwoPrim")
|
||||
.add(factory.newPrimitiveProperty(
|
||||
"PropertyInt16",
|
||||
factory.newPrimitiveValueBuilder().buildInt16((short) 1)))
|
||||
.add(factory.newPrimitiveProperty(
|
||||
"PropertyString",
|
||||
factory.newPrimitiveValueBuilder().buildString("Test2")))));
|
||||
|
||||
final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESKeyNav").build();
|
||||
ODataEntityCreateRequest<ODataEntity> request =
|
||||
client.getCUDRequestFactory().getEntityCreateRequest(uri, newEntity);
|
||||
ODataEntityCreateResponse<ODataEntity> response = request.execute();
|
||||
assertEquals(HttpStatusCode.CREATED.getStatusCode(), response.getStatusCode());
|
||||
|
||||
final String cookie = response.getHeader(HttpHeader.SET_COOKIE).iterator().next();
|
||||
|
||||
// Do the filter request
|
||||
ODataRetrieveResponse<ODataEntitySet> result =
|
||||
sendRequest("ESKeyNav", "PropertyCompComp/PropertyComp/PropertyInt16 eq 1", cookie);
|
||||
assertEquals(3, result.getBody().getEntities().size());
|
||||
|
||||
// Try filter all entries where PropertyCompComp is null
|
||||
result = sendRequest("ESKeyNav", "PropertyCompComp/PropertyComp/PropertyInt16 eq null", cookie);
|
||||
assertEquals(1, result.getBody().getEntities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSringFunctionWithoutStringParameters() {
|
||||
fail("ESServerSidePaging", "filter=contains(PropertyInt16, 3) eq 'hallo'", HttpStatusCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
private ODataRetrieveResponse<ODataEntitySet> sendRequest(String entitySet, String filterString) {
|
||||
return sendRequest(entitySet, filterString, null);
|
||||
}
|
||||
|
||||
private ODataRetrieveResponse<ODataEntitySet> sendRequest(String entitySet, String filterString, String cookie) {
|
||||
final ODataClient client = getClient();
|
||||
|
||||
final URI uri =
|
||||
client.newURIBuilder(SERVICE_URI)
|
||||
.appendEntitySetSegment(entitySet)
|
||||
.filter(filterString)
|
||||
.build();
|
||||
|
||||
ODataEntitySetRequest<ODataEntitySet> request = client.getRetrieveRequestFactory().getEntitySetRequest(uri);
|
||||
if (cookie != null) {
|
||||
request.addCustomHeader(HttpHeader.COOKIE, cookie);
|
||||
}
|
||||
|
||||
return request.execute();
|
||||
}
|
||||
|
||||
private void fail(String entitySet, String filterString, HttpStatusCode errorCode) {
|
||||
try {
|
||||
sendRequest(entitySet, filterString);
|
||||
Assert.fail();
|
||||
} catch (ODataClientErrorException e) {
|
||||
assertEquals(errorCode.getStatusCode(), e.getStatusLine().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ODataClient getClient() {
|
||||
ODataClient odata = ODataClientFactory.getV4();
|
||||
odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON);
|
||||
return odata;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* 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.fit.tecsvc.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.apache.olingo.client.api.ODataClient;
|
||||
import org.apache.olingo.client.api.communication.ODataClientErrorException;
|
||||
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
|
||||
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
|
||||
import org.apache.olingo.client.core.ODataClientFactory;
|
||||
import org.apache.olingo.commons.api.domain.ODataEntity;
|
||||
import org.apache.olingo.commons.api.domain.ODataEntitySet;
|
||||
import org.apache.olingo.commons.api.domain.ODataValuable;
|
||||
import org.apache.olingo.commons.api.format.ODataFormat;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.fit.AbstractBaseTestITCase;
|
||||
import org.apache.olingo.fit.tecsvc.TecSvcConst;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OrderBySystemQueryITCase extends AbstractBaseTestITCase {
|
||||
|
||||
private static final String ES_TWO_PRIM = "ESTwoPrim";
|
||||
private static final String ES_ALL_PRIM = "ESAllPrim";
|
||||
|
||||
private static final String SERVICE_URI = TecSvcConst.BASE_URI;
|
||||
|
||||
@AfterClass
|
||||
public static void tearDownAfterClass() throws Exception {}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderBy() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response = null;
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyDate");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(1);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(2);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderByDecending() {
|
||||
ODataRetrieveResponse<ODataEntitySet> response = null;
|
||||
|
||||
response = sendRequest(ES_ALL_PRIM, "PropertyDate desc");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(1);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(2);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleOrderBy() {
|
||||
final ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyByte, PropertyInt16");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(1);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(2);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleOrderByDecending() {
|
||||
final ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_ALL_PRIM, "PropertyByte, PropertyInt16 desc");
|
||||
assertEquals(3, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("0", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(1);
|
||||
assertEquals("-32768", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(2);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderByWithNull() {
|
||||
final ODataRetrieveResponse<ODataEntitySet> response = sendRequest(ES_TWO_PRIM, "PropertyString");
|
||||
assertEquals(4, response.getBody().getEntities().size());
|
||||
|
||||
ODataEntity oDataEntity = response.getBody().getEntities().get(0);
|
||||
assertEquals("-32766", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(1);
|
||||
assertEquals("32766", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(2);
|
||||
assertEquals("-365", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
|
||||
oDataEntity = response.getBody().getEntities().get(3);
|
||||
assertEquals("32767", ((ODataValuable) oDataEntity.getProperty("PropertyInt16")).getValue().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrderByInvalidExpression() {
|
||||
fail(ES_TWO_PRIM, "PropertyString add 10", HttpStatusCode.BAD_REQUEST);
|
||||
}
|
||||
|
||||
private ODataRetrieveResponse<ODataEntitySet> sendRequest(String entitySet, String orderByString) {
|
||||
final ODataClient client = getClient();
|
||||
String escapedFilterString = escapeFilterString(orderByString);
|
||||
|
||||
final URI uri =
|
||||
client.newURIBuilder(SERVICE_URI)
|
||||
.appendEntitySetSegment(entitySet)
|
||||
.orderBy(escapedFilterString)
|
||||
.build();
|
||||
|
||||
ODataEntitySetRequest<ODataEntitySet> request = client.getRetrieveRequestFactory().getEntitySetRequest(uri);
|
||||
|
||||
return request.execute();
|
||||
}
|
||||
|
||||
private void fail(String entitySet, String filterString, HttpStatusCode errorCode) {
|
||||
try {
|
||||
sendRequest(entitySet, filterString);
|
||||
Assert.fail();
|
||||
} catch (ODataClientErrorException e) {
|
||||
assertEquals(errorCode.getStatusCode(), e.getStatusLine().getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
private String escapeFilterString(String filterString) {
|
||||
return filterString.replace(" ", "%20");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ODataClient getClient() {
|
||||
ODataClient odata = ODataClientFactory.getV4();
|
||||
odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON);
|
||||
return odata;
|
||||
}
|
||||
}
|
|
@ -311,7 +311,6 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
|
|||
// it will try to call URLEncodedUtils.format(Iterable<>,Charset) method,
|
||||
// which works in desktop java application, however, throws NoSuchMethodError in android OS,
|
||||
// so here manually construct the URL by its overload URLEncodedUtils.format(List<>,String).
|
||||
//String queryStr = URLEncodedUtils.format(list1, "UTF-8");
|
||||
final String queryStr = encodeQueryParameter(list1);
|
||||
sb.append(queryStr);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.http.HttpContentType;
|
|||
import org.apache.olingo.commons.api.http.HttpHeader;
|
||||
import org.apache.olingo.commons.api.http.HttpMethod;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.data.EntitySetImpl;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.ODataRequest;
|
||||
import org.apache.olingo.server.api.ODataResponse;
|
||||
|
@ -52,13 +53,14 @@ import org.apache.olingo.server.api.uri.UriResourceEntitySet;
|
|||
import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.SelectOption;
|
||||
import org.apache.olingo.server.tecsvc.data.DataProvider;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.FilterSystemQueryHandler;
|
||||
|
||||
/**
|
||||
* Technical Processor for entity-related functionality.
|
||||
*/
|
||||
public class TechnicalEntityProcessor extends TechnicalProcessor
|
||||
implements EntityCollectionProcessor, ActionEntityCollectionProcessor, CountEntityCollectionProcessor,
|
||||
EntityProcessor, ActionEntityProcessor, MediaEntityProcessor {
|
||||
EntityProcessor, ActionEntityProcessor, MediaEntityProcessor {
|
||||
|
||||
public TechnicalEntityProcessor(final DataProvider dataProvider) {
|
||||
super(dataProvider);
|
||||
|
@ -68,14 +70,21 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
public void readEntityCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
|
||||
final ContentType requestedContentType) throws ODataApplicationException, SerializerException {
|
||||
validateOptions(uriInfo.asUriInfoResource());
|
||||
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo);
|
||||
EntitySet entitySet = readEntityCollection(uriInfo);
|
||||
if (entitySet == null) {
|
||||
|
||||
final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
|
||||
final EntitySet entitySetInitial = readEntityCollection(uriInfo);
|
||||
if (entitySetInitial == null) {
|
||||
throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
|
||||
} else {
|
||||
if (uriInfo.getCountOption() != null && uriInfo.getCountOption().getValue()) {
|
||||
setCount(entitySet);
|
||||
}
|
||||
// Modifying the original entitySet means modifying the "database", so we have to make a shallow
|
||||
// copy of the entity set (new EntitySet, but exactly the same data)
|
||||
EntitySet entitySet = new EntitySetImpl();
|
||||
entitySet.getEntities().addAll(entitySetInitial.getEntities());
|
||||
|
||||
// Apply system query options
|
||||
FilterSystemQueryHandler.applyFilterSystemQuery(uriInfo.getFilterOption(), entitySet, edmEntitySet);
|
||||
FilterSystemQueryHandler.applyOrderByOption(uriInfo.getOrderByOption(), entitySet, edmEntitySet);
|
||||
|
||||
final ODataFormat format = ODataFormat.fromContentType(requestedContentType);
|
||||
ODataSerializer serializer = odata.createSerializer(format);
|
||||
final ExpandOption expand = uriInfo.getExpandOption();
|
||||
|
@ -95,7 +104,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
@Override
|
||||
public void processActionEntityCollection(final ODataRequest request, final ODataResponse response,
|
||||
final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
throw new ODataApplicationException("Process entity collection is not supported yet.",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
@ -150,7 +159,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
@Override
|
||||
public void createMediaEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
|
||||
final ContentType requestFormat, final ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
createEntity(request, response, uriInfo, requestFormat, responseFormat);
|
||||
}
|
||||
|
||||
|
@ -168,9 +177,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
|
||||
|
||||
Entity entity = dataProvider.create(edmEntitySet);
|
||||
if (edmEntityType.hasStream()) { // called from createMediaEntity(...), not directly
|
||||
if (edmEntityType.hasStream()) { // called from createMediaEntity(...), not directly
|
||||
dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()),
|
||||
requestFormat.toContentTypeString());
|
||||
requestFormat.toContentTypeString());
|
||||
} else {
|
||||
dataProvider.update(edmEntitySet, entity,
|
||||
odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
|
||||
|
@ -228,7 +237,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
|
|||
@Override
|
||||
public void processActionEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
|
||||
final ContentType requestFormat, final ContentType responseFormat)
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
throws ODataApplicationException, DeserializerException, SerializerException {
|
||||
throw new ODataApplicationException("Process entity is not supported yet.",
|
||||
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
|
|
@ -156,9 +156,7 @@ public abstract class TechnicalProcessor implements Processor {
|
|||
protected void validateOptions(final UriInfoResource uriInfo) throws ODataApplicationException {
|
||||
if (uriInfo.getCountOption() != null
|
||||
|| !uriInfo.getCustomQueryOptions().isEmpty()
|
||||
|| uriInfo.getFilterOption() != null
|
||||
|| uriInfo.getIdOption() != null
|
||||
|| uriInfo.getOrderByOption() != null
|
||||
|| uriInfo.getSearchOption() != null
|
||||
|| uriInfo.getSkipOption() != null
|
||||
|| uriInfo.getSkipTokenOption() != null
|
||||
|
|
|
@ -0,0 +1,236 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.Property;
|
||||
import org.apache.olingo.commons.api.edm.EdmComplexType;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEnumType;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.uri.UriInfoResource;
|
||||
import org.apache.olingo.server.api.uri.UriResource;
|
||||
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.Expression;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.MethodKind;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.UnaryOperatorKind;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.UntypedOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operation.BinaryOperator;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operation.MethodCallOperator;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operation.UnaryOperator;
|
||||
|
||||
public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand> {
|
||||
|
||||
final private Entity entity;
|
||||
final private EdmEntitySet edmEntitySet;
|
||||
|
||||
public ExpressionVisitorImpl(Entity entity, EdmEntitySet edmEntitySet) {
|
||||
this.entity = entity;
|
||||
this.edmEntitySet = edmEntitySet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitBinaryOperator(BinaryOperatorKind operator, VisitorOperand left, VisitorOperand right)
|
||||
throws ExpressionVisitException, ODataApplicationException {
|
||||
|
||||
final BinaryOperator binaryOperator = new BinaryOperator(left, right);
|
||||
|
||||
switch (operator) {
|
||||
case AND:
|
||||
return binaryOperator.andOperator();
|
||||
case OR:
|
||||
return binaryOperator.orOperator();
|
||||
case EQ:
|
||||
return binaryOperator.equalsOperator();
|
||||
case NE:
|
||||
return binaryOperator.notEqualsOperator();
|
||||
case GE:
|
||||
return binaryOperator.greaterEqualsOperator();
|
||||
case GT:
|
||||
return binaryOperator.greaterThanOperator();
|
||||
case LE:
|
||||
return binaryOperator.lessEqualsOperator();
|
||||
case LT:
|
||||
return binaryOperator.lessThanOperator();
|
||||
case ADD:
|
||||
case SUB:
|
||||
case MUL:
|
||||
case DIV:
|
||||
case MOD:
|
||||
return binaryOperator.arithmeticOperator(operator);
|
||||
default:
|
||||
return throwNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitUnaryOperator(UnaryOperatorKind operator, VisitorOperand operand)
|
||||
throws ExpressionVisitException, ODataApplicationException {
|
||||
|
||||
final UnaryOperator unaryOperator = new UnaryOperator(operand);
|
||||
|
||||
switch (operator) {
|
||||
case MINUS:
|
||||
return unaryOperator.minusOperation();
|
||||
case NOT:
|
||||
return unaryOperator.notOperation();
|
||||
default:
|
||||
// Can`t happen
|
||||
return throwNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitMethodCall(MethodKind methodCall, List<VisitorOperand> parameters)
|
||||
throws ExpressionVisitException, ODataApplicationException {
|
||||
|
||||
final MethodCallOperator methodCallOperation = new MethodCallOperator(parameters);
|
||||
|
||||
switch (methodCall) {
|
||||
case ENDSWITH:
|
||||
return methodCallOperation.endsWith();
|
||||
case INDEXOF:
|
||||
return methodCallOperation.indexOf();
|
||||
case STARTSWITH:
|
||||
return methodCallOperation.startsWith();
|
||||
case TOLOWER:
|
||||
return methodCallOperation.toLower();
|
||||
case TOUPPER:
|
||||
return methodCallOperation.toUpper();
|
||||
case TRIM:
|
||||
return methodCallOperation.trim();
|
||||
case SUBSTRING:
|
||||
return methodCallOperation.substring();
|
||||
case CONTAINS:
|
||||
return methodCallOperation.contains();
|
||||
case CONCAT:
|
||||
return methodCallOperation.concat();
|
||||
case LENGTH:
|
||||
return methodCallOperation.length();
|
||||
case YEAR:
|
||||
return methodCallOperation.year();
|
||||
case MONTH:
|
||||
return methodCallOperation.month();
|
||||
case DAY:
|
||||
return methodCallOperation.day();
|
||||
case HOUR:
|
||||
return methodCallOperation.hour();
|
||||
case MINUTE:
|
||||
return methodCallOperation.minute();
|
||||
case SECOND:
|
||||
return methodCallOperation.second();
|
||||
case FRACTIONALSECONDS:
|
||||
return methodCallOperation.fractionalseconds();
|
||||
case ROUND:
|
||||
return methodCallOperation.round();
|
||||
case FLOOR:
|
||||
return methodCallOperation.floor();
|
||||
case CEILING:
|
||||
return methodCallOperation.ceiling();
|
||||
|
||||
default:
|
||||
return throwNotImplemented();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitLambdaExpression(String lambdaFunction, String lambdaVariable, Expression expression)
|
||||
throws ExpressionVisitException, ODataApplicationException {
|
||||
|
||||
return throwNotImplemented();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitLiteral(String literal) throws ExpressionVisitException, ODataApplicationException {
|
||||
|
||||
return new UntypedOperand(literal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitMember(UriInfoResource member) throws ExpressionVisitException,
|
||||
ODataApplicationException {
|
||||
|
||||
final List<UriResource> uriResourceParts = member.getUriResourceParts();
|
||||
|
||||
// UriResourceParts contains at least one UriResource
|
||||
Property currentProperty = entity.getProperty(uriResourceParts.get(0).toString());
|
||||
EdmType currentType = ((UriResourcePartTyped) uriResourceParts.get(0)).getType();
|
||||
|
||||
EdmProperty currentEdmProperty = edmEntitySet.getEntityType()
|
||||
.getStructuralProperty(uriResourceParts.get(0).toString());
|
||||
|
||||
for (int i = 1; i < uriResourceParts.size(); i++) {
|
||||
currentType = ((UriResourcePartTyped) uriResourceParts.get(i)).getType();
|
||||
|
||||
if (currentProperty.isComplex() || currentProperty.isLinkedComplex()) {
|
||||
final List<Property> complex = currentProperty.isLinkedComplex() ?
|
||||
currentProperty.asLinkedComplex().getValue() : currentProperty.asComplex();
|
||||
|
||||
for (final Property innerProperty : complex) {
|
||||
if (innerProperty.getName().equals(uriResourceParts.get(i).toString())) {
|
||||
EdmComplexType edmComplexType = (EdmComplexType) currentEdmProperty.getType();
|
||||
currentEdmProperty = edmComplexType.getStructuralProperty(uriResourceParts.get(i).toString());
|
||||
currentProperty = innerProperty;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TypedOperand(((Property) currentProperty).getValue(), currentType, currentEdmProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitAlias(String aliasName) throws ExpressionVisitException, ODataApplicationException {
|
||||
return throwNotImplemented();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitTypeLiteral(EdmType type) throws ExpressionVisitException, ODataApplicationException {
|
||||
return throwNotImplemented();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitLambdaReference(String variableName) throws ExpressionVisitException,
|
||||
ODataApplicationException {
|
||||
return throwNotImplemented();
|
||||
}
|
||||
|
||||
@Override
|
||||
public VisitorOperand visitEnum(EdmEnumType type, List<String> enumValues) throws ExpressionVisitException,
|
||||
ODataApplicationException {
|
||||
return throwNotImplemented();
|
||||
}
|
||||
|
||||
private VisitorOperand throwNotImplemented() throws ODataApplicationException {
|
||||
throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression;
|
||||
|
||||
import org.apache.olingo.commons.api.ODataRuntimeException;
|
||||
|
||||
public class FilterRuntimeException extends ODataRuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public FilterRuntimeException(Exception cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public FilterRuntimeException(String msg, Exception cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
public FilterRuntimeException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.data.Entity;
|
||||
import org.apache.olingo.commons.api.data.EntitySet;
|
||||
import org.apache.olingo.commons.api.edm.EdmEntitySet;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.uri.queryoption.FilterOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.OrderByItem;
|
||||
import org.apache.olingo.server.api.uri.queryoption.OrderByOption;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitException;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
|
||||
|
||||
public class FilterSystemQueryHandler {
|
||||
|
||||
public static void applyFilterSystemQuery(FilterOption filterOption, EntitySet entitySet, EdmEntitySet edmEntitySet)
|
||||
throws ODataApplicationException {
|
||||
|
||||
if (filterOption == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final Iterator<Entity> iter = entitySet.getEntities().iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
final VisitorOperand operand = filterOption.getExpression()
|
||||
.accept(new ExpressionVisitorImpl(iter.next(), edmEntitySet));
|
||||
final TypedOperand typedOperand = operand.asTypedOperand();
|
||||
|
||||
if (!(typedOperand.is(EdmBoolean.getInstance())
|
||||
&& Boolean.TRUE.equals(typedOperand.getTypedValue(Boolean.class)))) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (ExpressionVisitException e) {
|
||||
throw new ODataApplicationException("Exception in filter evaluation",
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public static void applyOrderByOption(final OrderByOption orderByOption, final EntitySet entitySet,
|
||||
final EdmEntitySet edmEntitySet) throws ODataApplicationException {
|
||||
|
||||
if (orderByOption == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
applyOrderByOptionInternal(orderByOption, entitySet, edmEntitySet);
|
||||
} catch (FilterRuntimeException e) {
|
||||
if (e.getCause() instanceof ODataApplicationException) {
|
||||
// Throw the nested exception, to send the correct HTTP status code in the HTTP response
|
||||
throw (ODataApplicationException) e.getCause();
|
||||
} else {
|
||||
throw new ODataApplicationException("Exception in orderBy evaluation", HttpStatusCode.INTERNAL_SERVER_ERROR
|
||||
.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyOrderByOptionInternal(final OrderByOption orderByOption, final EntitySet entitySet,
|
||||
final EdmEntitySet edmEntitySet) throws ODataApplicationException {
|
||||
Collections.sort(entitySet.getEntities(), new Comparator<Entity>() {
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public int compare(final Entity e1, final Entity e2) {
|
||||
// Evaluate the first order option for both entity
|
||||
// If and only if the result of the previous order option is equals to 0
|
||||
// evaluate the next order option until all options are evaluated or they are not equals
|
||||
int result = 0;
|
||||
|
||||
for (int i = 0; i < orderByOption.getOrders().size() && result == 0; i++) {
|
||||
try {
|
||||
final OrderByItem item = orderByOption.getOrders().get(i);
|
||||
final TypedOperand op1 =
|
||||
item.getExpression().accept(new ExpressionVisitorImpl(e1, edmEntitySet)).asTypedOperand();
|
||||
final TypedOperand op2 =
|
||||
item.getExpression().accept(new ExpressionVisitorImpl(e2, edmEntitySet)).asTypedOperand();
|
||||
|
||||
if (op1.isNull() || op2.isNull()) {
|
||||
if (op1.isNull() && op2.isNull()) {
|
||||
result = 0; // null is equals to null
|
||||
} else {
|
||||
result = op1.isNull() ? -1 : 1;
|
||||
}
|
||||
} else {
|
||||
Object o1 = op1.getValue();
|
||||
Object o2 = op2.getValue();
|
||||
|
||||
if (o1.getClass() == o2.getClass() && o1 instanceof Comparable) {
|
||||
result = ((Comparable) o1).compareTo(o2);
|
||||
} else {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
result = item.isDescending() ? result * -1 : result;
|
||||
} catch (ODataApplicationException e) {
|
||||
throw new FilterRuntimeException(e);
|
||||
} catch (ExpressionVisitException e) {
|
||||
throw new FilterRuntimeException(e);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.operand;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
|
||||
|
||||
public class TypedOperand extends VisitorOperand {
|
||||
|
||||
final private EdmType type;
|
||||
final private EdmProperty edmProperty;
|
||||
|
||||
public TypedOperand(Object value, EdmType type) {
|
||||
super(value);
|
||||
this.type = type;
|
||||
this.edmProperty = null;
|
||||
}
|
||||
|
||||
public TypedOperand(Object value, EdmType type, EdmProperty edmProperty) {
|
||||
super(value);
|
||||
this.type = type;
|
||||
this.edmProperty = edmProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedOperand asTypedOperand() throws ODataApplicationException {
|
||||
if (!isNull() && value.getClass() != getDefaultType((EdmPrimitiveType) type)) {
|
||||
return asTypedOperand((EdmPrimitiveType) type);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedOperand asTypedOperand(EdmPrimitiveType... asTypes) throws ODataApplicationException {
|
||||
if (type.equals(EdmNull.getInstance())) {
|
||||
return this;
|
||||
} else if (isNull()) {
|
||||
return new TypedOperand(null, asTypes[0]);
|
||||
}
|
||||
|
||||
Object newValue = null;
|
||||
for (EdmPrimitiveType asType : asTypes) {
|
||||
// Use BigDecimal for unlimited precision
|
||||
if (asType.equals(EdmDouble.getInstance())
|
||||
|| asType.equals(EdmSingle.getInstance())
|
||||
|| asType.equals(EdmDecimal.getInstance())) {
|
||||
|
||||
try {
|
||||
newValue = new BigDecimal(value.toString());
|
||||
} catch(NumberFormatException e) {
|
||||
// Nothing to do
|
||||
}
|
||||
} else {
|
||||
// Use type conversion of EdmPrimitive types
|
||||
try {
|
||||
final String literal = getLiteral(value);
|
||||
newValue = tryCast(literal, (EdmPrimitiveType) type);
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
if (newValue != null) {
|
||||
return new TypedOperand(newValue, asType);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ODataApplicationException("Cast failed ", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
||||
public TypedOperand castToCommonType(VisitorOperand otherOperand) throws ODataApplicationException {
|
||||
final TypedOperand other = otherOperand.asTypedOperand();
|
||||
final EdmType oType = other.getType();
|
||||
|
||||
// Make sure that the EDM type is equals, check also the java type.
|
||||
// So it is possible, that there is an conversation even if the same
|
||||
// EdmType is provided.
|
||||
// For example consider an Edm16 (internal Integer) and Edm16(internal
|
||||
// Short)
|
||||
// shortInstance.equals(intInstance) will always be false!
|
||||
if (type == oType && value != null && other.getValue() != null
|
||||
&& value.getClass() == other.getValue().getClass()) {
|
||||
return this;
|
||||
} else if (isNullLiteral() || other.isNullLiteral()) {
|
||||
return this;
|
||||
}
|
||||
|
||||
if (type.equals(EdmDouble.getInstance()) || oType.equals(EdmDouble.getInstance())) {
|
||||
return asTypedOperand(EdmDouble.getInstance());
|
||||
} else if (type.equals(EdmSingle.getInstance()) || oType.equals(EdmSingle.getInstance())) {
|
||||
return asTypedOperand(EdmSingle.getInstance());
|
||||
} else if (type.equals(EdmDecimal.getInstance()) || oType.equals(EdmDecimal.getInstance())) {
|
||||
return asTypedOperand(EdmDecimal.getInstance());
|
||||
} else if (type.equals(EdmInt64.getInstance()) || oType.equals(EdmInt64.getInstance())) {
|
||||
return asTypedOperand(EdmInt64.getInstance());
|
||||
} else if (type.equals(EdmInt32.getInstance()) || oType.equals(EdmInt32.getInstance())) {
|
||||
return asTypedOperand(EdmInt32.getInstance());
|
||||
} else if (type.equals(EdmInt16.getInstance()) || oType.equals(equals(EdmInt16.getInstance()))) {
|
||||
return asTypedOperand(EdmInt16.getInstance());
|
||||
} else {
|
||||
return asTypedOperand((EdmPrimitiveType) type);
|
||||
}
|
||||
}
|
||||
|
||||
public EdmType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public <T> T getTypedValue(Class<T> clazz) {
|
||||
return clazz.cast(value);
|
||||
}
|
||||
|
||||
public boolean isNullLiteral() {
|
||||
return type.equals(EdmNull.getInstance());
|
||||
}
|
||||
|
||||
public boolean isNull() {
|
||||
return isNullLiteral() || value == null;
|
||||
}
|
||||
|
||||
public boolean isIntegerType() {
|
||||
return is(EdmByte.getInstance(),
|
||||
EdmSByte.getInstance(),
|
||||
EdmInt16.getInstance(),
|
||||
EdmInt32.getInstance(),
|
||||
EdmInt64.getInstance());
|
||||
}
|
||||
|
||||
public boolean isDecimalType() {
|
||||
return is(EdmSingle.getInstance(),
|
||||
EdmDouble.getInstance(),
|
||||
EdmDecimal.getInstance());
|
||||
}
|
||||
|
||||
public boolean is(EdmPrimitiveType... types) {
|
||||
if (isNullLiteral()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (EdmPrimitiveType type : types) {
|
||||
if (type.equals(this.type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmProperty getEdmProperty() {
|
||||
return edmProperty;
|
||||
}
|
||||
|
||||
private String getLiteral(Object value) throws EdmPrimitiveTypeException {
|
||||
final EdmProperty edmProperty = getEdmProperty();
|
||||
String uriLiteral = null;
|
||||
|
||||
if (edmProperty != null) {
|
||||
uriLiteral = ((EdmPrimitiveType) type).valueToString(value, edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode());
|
||||
} else {
|
||||
uriLiteral = ((EdmPrimitiveType) type).valueToString(value, null, null, null, null, null);
|
||||
}
|
||||
|
||||
return ((EdmPrimitiveType) type).toUriLiteral(uriLiteral);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.operand;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmTime;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
|
||||
|
||||
public class UntypedOperand extends VisitorOperand {
|
||||
|
||||
public UntypedOperand(final String literal) {
|
||||
super(literal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedOperand asTypedOperand() throws ODataApplicationException {
|
||||
return determineType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedOperand asTypedOperand(final EdmPrimitiveType... types) throws ODataApplicationException {
|
||||
final String literal = (String) value;
|
||||
Object newValue = null;
|
||||
|
||||
// First try the null literal
|
||||
if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmNull.getInstance());
|
||||
}
|
||||
|
||||
// Than try the given types
|
||||
for (EdmPrimitiveType type : types) {
|
||||
newValue = tryCast(literal, type);
|
||||
|
||||
if (newValue != null) {
|
||||
return new TypedOperand(newValue, type);
|
||||
}
|
||||
}
|
||||
|
||||
throw new ODataApplicationException("Cast failed", HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
|
||||
public TypedOperand determineType() throws ODataApplicationException {
|
||||
final String literal = (String) value;
|
||||
Object newValue = null;
|
||||
|
||||
// Null literal
|
||||
if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmNull.getInstance());
|
||||
}
|
||||
|
||||
// String
|
||||
if ((newValue = tryCast(literal, EdmString.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmString.getInstance());
|
||||
}
|
||||
|
||||
// Date
|
||||
if ((newValue = tryCast(literal, EdmDateTimeOffset.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmDateTimeOffset.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmDate.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmDate.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmTimeOfDay.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmTimeOfDay.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmTime.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmTime.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmDuration.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmDuration.getInstance());
|
||||
}
|
||||
|
||||
// Integer
|
||||
if ((newValue = tryCast(literal, EdmSByte.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmSByte.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmByte.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmByte.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmInt16.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmInt16.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmInt32.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmInt32.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmInt64.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmInt64.getInstance());
|
||||
}
|
||||
|
||||
// Decimal
|
||||
if ((newValue = tryCast(literal, EdmDecimal.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmDecimal.getInstance());
|
||||
}
|
||||
|
||||
// Float
|
||||
if ((newValue = tryCast(literal, EdmSingle.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmSingle.getInstance());
|
||||
}
|
||||
|
||||
if ((newValue = tryCast(literal, EdmDouble.getInstance())) != null) {
|
||||
return new TypedOperand(newValue, EdmDouble.getInstance());
|
||||
}
|
||||
|
||||
throw new ODataApplicationException("Could not determine type for literal " + literal,
|
||||
HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdmProperty getEdmProperty() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.operand;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.api.edm.EdmProperty;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
|
||||
public abstract class VisitorOperand {
|
||||
final static private HashMap<EdmType, Class<?>> defaultTypeMapping = new HashMap<EdmType, Class<?>>();
|
||||
protected Object value;
|
||||
|
||||
static {
|
||||
defaultTypeMapping.put(EdmByte.getInstance(), BigInteger.class);
|
||||
defaultTypeMapping.put(EdmSByte.getInstance(), BigInteger.class);
|
||||
defaultTypeMapping.put(EdmInt16.getInstance(), BigInteger.class);
|
||||
defaultTypeMapping.put(EdmInt32.getInstance(), BigInteger.class);
|
||||
defaultTypeMapping.put(EdmInt64.getInstance(), BigInteger.class);
|
||||
|
||||
defaultTypeMapping.put(EdmSingle.getInstance(), BigDecimal.class);
|
||||
defaultTypeMapping.put(EdmDouble.getInstance(), BigDecimal.class);
|
||||
defaultTypeMapping.put(EdmDecimal.getInstance(), BigDecimal.class);
|
||||
}
|
||||
|
||||
public VisitorOperand(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public abstract TypedOperand asTypedOperand() throws ODataApplicationException;
|
||||
|
||||
public abstract TypedOperand asTypedOperand(EdmPrimitiveType... types) throws ODataApplicationException;
|
||||
|
||||
public abstract EdmProperty getEdmProperty();
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected Object castTo(final String value, EdmPrimitiveType type) throws EdmPrimitiveTypeException {
|
||||
final EdmProperty edmProperty = getEdmProperty();
|
||||
|
||||
if (edmProperty != null) {
|
||||
return type.valueOfString(value, edmProperty.isNullable(), edmProperty.getMaxLength(),
|
||||
edmProperty.getPrecision(), edmProperty.getScale(),
|
||||
edmProperty.isUnicode(), getDefaultType(type));
|
||||
} else {
|
||||
return type.valueOfString(value, null, null, null, null, null, getDefaultType(type));
|
||||
}
|
||||
}
|
||||
|
||||
protected Class<?> getDefaultType(EdmPrimitiveType type) {
|
||||
return defaultTypeMapping.get(type) != null ? defaultTypeMapping.get(type) : type.getDefaultType();
|
||||
}
|
||||
|
||||
protected Object tryCast(final String literal, final EdmPrimitiveType type) {
|
||||
try {
|
||||
return castTo(type.fromUriLiteral(literal), type);
|
||||
} catch (EdmPrimitiveTypeException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.operation;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Calendar;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDouble;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt16;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt64;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSByte;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.api.uri.queryoption.expression.BinaryOperatorKind;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.primitive.EdmNull;
|
||||
|
||||
public class BinaryOperator {
|
||||
private static final int FACTOR_SECOND_INT = 1000;
|
||||
private static final BigDecimal FACTOR_SECOND = new BigDecimal(1000);
|
||||
private static final BigInteger EDM_SBYTE_MIN = BigInteger.valueOf(Byte.MIN_VALUE);
|
||||
private static final BigInteger EDN_SBYTE_MAX = BigInteger.valueOf(Byte.MAX_VALUE);
|
||||
private static final BigInteger EDM_BYTE_MIN = BigInteger.ZERO;
|
||||
private static final BigInteger EDM_BYTE_MAX = BigInteger.valueOf(((Byte.MAX_VALUE * 2) + 1));
|
||||
private static final BigInteger EDM_INT16_MIN = BigInteger.valueOf(Short.MIN_VALUE);
|
||||
private static final BigInteger EDM_INT16_MAX = BigInteger.valueOf(Short.MAX_VALUE);
|
||||
private static final BigInteger EDM_INT32_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
|
||||
private static final BigInteger EDM_INT32_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
|
||||
private static final BigInteger EDM_INT64_MIN = BigInteger.valueOf(Long.MIN_VALUE);
|
||||
private static final BigInteger EDM_INT64_MAX = BigInteger.valueOf(Long.MAX_VALUE);
|
||||
private static final BigDecimal EDM_SINGLE_MIN = BigDecimal.valueOf(Float.MIN_VALUE);
|
||||
private static final BigDecimal EDM_SINGLE_MAX = BigDecimal.valueOf(Float.MAX_VALUE);
|
||||
|
||||
private static final int EQUALS = 0;
|
||||
private static final int LESS_THAN = -1;
|
||||
private static final int GREATER_THAN = 1;
|
||||
|
||||
private TypedOperand right;
|
||||
private TypedOperand left;
|
||||
|
||||
public BinaryOperator(final VisitorOperand leftOperand, final VisitorOperand rightOperand)
|
||||
throws ODataApplicationException {
|
||||
left = leftOperand.asTypedOperand();
|
||||
right = rightOperand.asTypedOperand();
|
||||
|
||||
left = left.castToCommonType(right);
|
||||
right = right.castToCommonType(left);
|
||||
}
|
||||
|
||||
public VisitorOperand andOperator() throws ODataApplicationException {
|
||||
Boolean result = null;
|
||||
if (left.is(EdmBoolean.getInstance()) && right.is(EdmBoolean.getInstance())) {
|
||||
if (Boolean.TRUE.equals(left.getValue()) && Boolean.TRUE.equals(right.getValue())) {
|
||||
result = true;
|
||||
} else if (Boolean.FALSE.equals(left.getValue()) || Boolean.FALSE.equals(right.getValue())) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
} else {
|
||||
throw new ODataApplicationException("Add operator needs two binary operands",
|
||||
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public VisitorOperand orOperator() throws ODataApplicationException {
|
||||
Boolean result = null;
|
||||
if (left.is(EdmBoolean.getInstance()) && right.is(EdmBoolean.getInstance())) {
|
||||
if (Boolean.TRUE.equals(left.getValue()) || Boolean.TRUE.equals(right.getValue())) {
|
||||
result = true;
|
||||
} else if (Boolean.FALSE.equals(left.getValue()) && Boolean.FALSE.equals(right.getValue())) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
} else {
|
||||
throw new ODataApplicationException("Or operator needs two binary operands",
|
||||
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public VisitorOperand equalsOperator() {
|
||||
final boolean result = isBinaryComparisonNecessary() && binaryComparison(EQUALS);
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand notEqualsOperator() {
|
||||
final VisitorOperand equalsOperator = equalsOperator();
|
||||
return new TypedOperand(!(Boolean) equalsOperator.getValue(), EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
private boolean isBinaryComparisonNecessary() {
|
||||
// binaryComparison() need to be called, if both operand are either null or not null
|
||||
return !(left.isNull() ^ right.isNull());
|
||||
}
|
||||
|
||||
public VisitorOperand greaterEqualsOperator() {
|
||||
final boolean result = isBinaryComparisonNecessary() && binaryComparison(GREATER_THAN, EQUALS);
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand greaterThanOperator() {
|
||||
final boolean result = isBinaryComparisonNecessary() && binaryComparison(GREATER_THAN);
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand lessEqualsOperator() {
|
||||
final boolean result = isBinaryComparisonNecessary() && binaryComparison(LESS_THAN, EQUALS);
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand lessThanOperator() {
|
||||
final boolean result = isBinaryComparisonNecessary() && binaryComparison(LESS_THAN);
|
||||
return new TypedOperand(result, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
private boolean binaryComparison(int... expect) {
|
||||
int result;
|
||||
|
||||
if (left.isNull() && right.isNull()) {
|
||||
result = 0; // null is equals to null
|
||||
} else {
|
||||
// left and right are not null!
|
||||
if (left.isIntegerType()) {
|
||||
result = left.getTypedValue(BigInteger.class).compareTo(right.getTypedValue(BigInteger.class));
|
||||
} else if (left.isDecimalType()) {
|
||||
result = left.getTypedValue(BigDecimal.class).compareTo(right.getTypedValue(BigDecimal.class));
|
||||
} else {
|
||||
result = left.getValue().equals(right.getValue()) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
for (int expectedValue : expect) {
|
||||
if (expectedValue == result) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public VisitorOperand arithmeticOperator(BinaryOperatorKind operator) throws ODataApplicationException {
|
||||
if (left.isNull() || right.isNull()) {
|
||||
return new TypedOperand(new Object(), EdmNull.getInstance());
|
||||
} else {
|
||||
if (left.isIntegerType()) {
|
||||
final BigInteger result = integerArithmeticOperation(operator);
|
||||
return new TypedOperand(result, determineResultType(result, left));
|
||||
} else if (left.isDecimalType()) {
|
||||
final BigDecimal result = decimalArithmeticOperation(operator);
|
||||
return new TypedOperand(result, determineResultType(result, left));
|
||||
} else if (left.is(EdmDate.getInstance(), EdmDuration.getInstance(), EdmDateTimeOffset.getInstance())) {
|
||||
return dateArithmeticOperation(operator);
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EdmType determineResultType(final Number arithmeticResult, TypedOperand leftOperand) {
|
||||
// Left and right operand have the same typed, so it is enough to check the type of the left operand
|
||||
if (leftOperand.isDecimalType()) {
|
||||
final BigDecimal value = (BigDecimal) arithmeticResult;
|
||||
if (value.compareTo(EDM_SINGLE_MIN) >= 0 && value.compareTo(EDM_SINGLE_MAX) <= 0) {
|
||||
return EdmSingle.getInstance();
|
||||
} else {
|
||||
return EdmDouble.getInstance();
|
||||
}
|
||||
} else {
|
||||
final BigInteger value = (BigInteger) arithmeticResult;
|
||||
|
||||
if (value.compareTo(EDN_SBYTE_MAX) <= 0 && value.compareTo(EDM_SBYTE_MIN) >= 0) {
|
||||
return EdmSByte.getInstance();
|
||||
}
|
||||
if (value.compareTo(EDM_BYTE_MAX) <= 0 && value.compareTo(EDM_BYTE_MIN) >= 0) {
|
||||
return EdmByte.getInstance();
|
||||
}
|
||||
if (value.compareTo(EDM_INT16_MAX) <= 0 && value.compareTo(EDM_INT16_MIN) >= 0) {
|
||||
return EdmInt16.getInstance();
|
||||
}
|
||||
if (value.compareTo(EDM_INT32_MAX) <= 0 && value.compareTo(EDM_INT32_MIN) >= 0) {
|
||||
return EdmInt32.getInstance();
|
||||
}
|
||||
if (value.compareTo(EDM_INT64_MAX) <= 0 && value.compareTo(EDM_INT64_MIN) >= 0) {
|
||||
return EdmInt64.getInstance();
|
||||
}
|
||||
// Choose double instead single because precision is higher (52 bits instead of 23)
|
||||
return EdmDouble.getInstance();
|
||||
}
|
||||
}
|
||||
|
||||
private VisitorOperand dateArithmeticOperation(BinaryOperatorKind operator) throws ODataApplicationException {
|
||||
VisitorOperand result = null;
|
||||
|
||||
if (left.is(EdmDate.getInstance())) {
|
||||
if (right.is(EdmDate.getInstance()) && operator == BinaryOperatorKind.SUB) {
|
||||
long millis = left.getTypedValue(Calendar.class).getTimeInMillis()
|
||||
- left.getTypedValue(Calendar.class).getTimeInMillis();
|
||||
|
||||
result = new TypedOperand(new BigDecimal(millis).divide(FACTOR_SECOND), EdmDuration.getInstance());
|
||||
} else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.ADD) {
|
||||
long millis = left.getTypedValue(Calendar.class).getTimeInMillis()
|
||||
+ (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
|
||||
|
||||
result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
|
||||
} else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.SUB) {
|
||||
long millis = left.getTypedValue(Calendar.class).getTimeInMillis()
|
||||
- (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
|
||||
|
||||
result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
|
||||
}
|
||||
} else if (left.is(EdmDuration.getInstance())) {
|
||||
if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.ADD) {
|
||||
long seconds = left.getTypedValue(BigDecimal.class).longValue()
|
||||
+ right.getTypedValue(BigDecimal.class).longValue();
|
||||
|
||||
result = new TypedOperand(new BigDecimal(seconds), EdmDuration.getInstance());
|
||||
} else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.SUB) {
|
||||
long seconds = left.getTypedValue(BigDecimal.class).longValue()
|
||||
- right.getTypedValue(BigDecimal.class).longValue();
|
||||
|
||||
result = new TypedOperand(new BigDecimal(seconds), EdmDuration.getInstance());
|
||||
}
|
||||
} else if (left.is(EdmDateTimeOffset.getInstance())) {
|
||||
if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.ADD) {
|
||||
long millis = left.getTypedValue(Timestamp.class).getTime()
|
||||
+ (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
|
||||
|
||||
result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
|
||||
} else if (right.is(EdmDuration.getInstance()) && operator == BinaryOperatorKind.SUB) {
|
||||
long millis = left.getTypedValue(Timestamp.class).getTime()
|
||||
- (right.getTypedValue(BigDecimal.class).longValue() * FACTOR_SECOND_INT);
|
||||
|
||||
result = new TypedOperand(new Timestamp(millis), EdmDateTimeOffset.getInstance());
|
||||
} else if (right.is(EdmDateTimeOffset.getInstance()) && operator == BinaryOperatorKind.SUB) {
|
||||
long millis = left.getTypedValue(Timestamp.class).getTime()
|
||||
- right.getTypedValue(Timestamp.class).getTime();
|
||||
|
||||
result = new TypedOperand(new BigDecimal(millis).divide(FACTOR_SECOND), EdmDuration.getInstance());
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
throw new ODataApplicationException("Invalid operation / operand", HttpStatusCode.BAD_REQUEST.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal decimalArithmeticOperation(BinaryOperatorKind operator) throws ODataApplicationException {
|
||||
final BigDecimal left = this.left.getTypedValue(BigDecimal.class);
|
||||
final BigDecimal right = this.right.getTypedValue(BigDecimal.class);
|
||||
|
||||
switch (operator) {
|
||||
case ADD:
|
||||
return left.add(right);
|
||||
case DIV:
|
||||
return left.divide(left);
|
||||
case MUL:
|
||||
return left.multiply(right);
|
||||
case SUB:
|
||||
return left.subtract(right);
|
||||
default:
|
||||
throw new ODataApplicationException("Operator not valid", HttpStatusCode.BAD_REQUEST.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
private BigInteger integerArithmeticOperation(BinaryOperatorKind operator) throws ODataApplicationException {
|
||||
final BigInteger left = this.left.getTypedValue(BigInteger.class);
|
||||
final BigInteger right = this.right.getTypedValue(BigInteger.class);
|
||||
|
||||
switch (operator) {
|
||||
case ADD:
|
||||
return left.add(right);
|
||||
case DIV:
|
||||
return left.divide(right);
|
||||
case MUL:
|
||||
return left.multiply(right);
|
||||
case SUB:
|
||||
return left.subtract(right);
|
||||
case MOD:
|
||||
return left.mod(right);
|
||||
default:
|
||||
throw new ODataApplicationException("Operator not valid", HttpStatusCode.BAD_REQUEST.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,334 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.operation;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
|
||||
import org.apache.olingo.commons.api.edm.EdmType;
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTimeOffset;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDecimal;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmInt32;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmString;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
|
||||
|
||||
public class MethodCallOperator {
|
||||
|
||||
final private List<VisitorOperand> parameters;
|
||||
|
||||
public MethodCallOperator(List<VisitorOperand> parameters) {
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public VisitorOperand endsWith() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).endsWith(params.get(1));
|
||||
}
|
||||
}, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand indexOf() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).indexOf(params.get(1));
|
||||
}
|
||||
}, EdmInt32.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand startsWith() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).startsWith(params.get(1));
|
||||
}
|
||||
}, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand toLower() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).toLowerCase();
|
||||
}
|
||||
}, EdmString.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand toUpper() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).toUpperCase();
|
||||
}
|
||||
}, EdmString.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand trim() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).trim();
|
||||
}
|
||||
}, EdmString.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand substring() throws ODataApplicationException {
|
||||
final TypedOperand valueOperand = parameters.get(0).asTypedOperand();
|
||||
final TypedOperand startOperand = parameters.get(1).asTypedOperand();
|
||||
|
||||
if (valueOperand.isNull() || startOperand.isNull()) {
|
||||
return new TypedOperand(null, EdmString.getInstance());
|
||||
} else if (valueOperand.is(EdmString.getInstance()) && startOperand.isIntegerType()) {
|
||||
final String value = valueOperand.getTypedValue(String.class);
|
||||
final BigInteger start = startOperand.getTypedValue(BigInteger.class);
|
||||
int end = value.length();
|
||||
|
||||
if (parameters.size() == 3) {
|
||||
final TypedOperand lengthOperand = parameters.get(2).asTypedOperand();
|
||||
|
||||
if (lengthOperand.isNull()) {
|
||||
return new TypedOperand(null, EdmString.getInstance());
|
||||
} else if (lengthOperand.isIntegerType()) {
|
||||
end = Math.min(start.add(lengthOperand.getTypedValue(BigInteger.class)).intValue(), value.length());
|
||||
} else {
|
||||
throw new ODataApplicationException("Third substring parameter should be Edm.Int32",
|
||||
HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
return new TypedOperand(value.substring(Math.min(start.intValue(), value.length()), end),
|
||||
EdmString.getInstance());
|
||||
} else {
|
||||
throw new ODataApplicationException("Substring has invalid parameters. First parameter should be Edm.String,"
|
||||
+ " second parameter should be Edm.Int32", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public VisitorOperand contains() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).contains(params.get(1));
|
||||
}
|
||||
}, EdmBoolean.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand concat() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0) + params.get(1);
|
||||
}
|
||||
}, EdmString.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand length() throws ODataApplicationException {
|
||||
return stringFunction(new StringFunction() {
|
||||
@Override
|
||||
public Object perform(List<String> params) {
|
||||
return params.get(0).length();
|
||||
}
|
||||
}, EdmInt32.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand year() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
return calendar.get(Calendar.YEAR);
|
||||
}
|
||||
}, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmDate.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand month() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
// Month is 0-based!
|
||||
return calendar.get(Calendar.MONTH) + 1;
|
||||
}
|
||||
}, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmDate.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand day() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
return calendar.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
}, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmDate.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand hour() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
return calendar.get(Calendar.HOUR_OF_DAY);
|
||||
}
|
||||
}, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand minute() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
return calendar.get(Calendar.MINUTE);
|
||||
}
|
||||
}, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand second() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
return calendar.get(Calendar.SECOND);
|
||||
}
|
||||
}, EdmInt32.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand fractionalseconds() throws ODataApplicationException {
|
||||
return dateFunction(new DateFunction() {
|
||||
@Override
|
||||
public Object perform(Calendar calendar, TypedOperand operand) {
|
||||
if (operand.getValue() instanceof Timestamp) {
|
||||
return new BigDecimal(operand.getTypedValue(Timestamp.class).getNanos()).divide(BigDecimal
|
||||
.valueOf(1000 * 1000 * 1000));
|
||||
} else {
|
||||
return new BigDecimal(calendar.get(Calendar.MILLISECOND)).divide(BigDecimal.valueOf(1000));
|
||||
}
|
||||
}
|
||||
}, EdmDecimal.getInstance(), EdmDateTimeOffset.getInstance(), EdmTimeOfDay.getInstance());
|
||||
}
|
||||
|
||||
public VisitorOperand round() throws ODataApplicationException {
|
||||
final TypedOperand operand = parameters.get(0).asTypedOperand();
|
||||
if (operand.isNull()) {
|
||||
return operand;
|
||||
} else if (operand.isDecimalType()) {
|
||||
return new TypedOperand(operand.getTypedValue(BigDecimal.class).round(new MathContext(1, RoundingMode.HALF_UP)),
|
||||
operand.getType());
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public VisitorOperand floor() throws ODataApplicationException {
|
||||
final TypedOperand operand = parameters.get(0).asTypedOperand();
|
||||
if (operand.isNull()) {
|
||||
return operand;
|
||||
} else if (operand.isDecimalType()) {
|
||||
return new TypedOperand(operand.getTypedValue(BigDecimal.class).round(new MathContext(1, RoundingMode.FLOOR)),
|
||||
operand.getType());
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public VisitorOperand ceiling() throws ODataApplicationException {
|
||||
final TypedOperand operand = parameters.get(0).asTypedOperand();
|
||||
if (operand.isNull()) {
|
||||
return operand;
|
||||
} else if (operand.isDecimalType()) {
|
||||
return new TypedOperand(operand.getTypedValue(BigDecimal.class).round(new MathContext(1, RoundingMode.CEILING)),
|
||||
operand.getType());
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
private interface StringFunction {
|
||||
Object perform(List<String> params);
|
||||
}
|
||||
|
||||
private interface DateFunction {
|
||||
Object perform(Calendar calendar, TypedOperand operand);
|
||||
}
|
||||
|
||||
private VisitorOperand dateFunction(DateFunction f, EdmType returnType, EdmPrimitiveType... expectedTypes)
|
||||
throws ODataApplicationException {
|
||||
final TypedOperand operand = parameters.get(0).asTypedOperand();
|
||||
|
||||
if (operand.is(expectedTypes)) {
|
||||
if (!operand.isNull()) {
|
||||
Calendar calendar = null;
|
||||
if (operand.is(EdmDate.getInstance())) {
|
||||
calendar = operand.getTypedValue(Calendar.class);
|
||||
} else if (operand.is(EdmDateTimeOffset.getInstance())) {
|
||||
final Timestamp timestamp = operand.getTypedValue(Timestamp.class);
|
||||
calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
|
||||
calendar.setTimeInMillis(timestamp.getTime());
|
||||
} else if (operand.is(EdmTimeOfDay.getInstance())) {
|
||||
calendar = operand.getTypedValue(Calendar.class);
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
|
||||
return new TypedOperand(f.perform(calendar, operand), returnType);
|
||||
} else {
|
||||
return new TypedOperand(null, returnType);
|
||||
}
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
private VisitorOperand stringFunction(StringFunction f, EdmType returnValue) throws ODataApplicationException {
|
||||
List<String> stringParameters = getParametersAsString();
|
||||
if (stringParameters.contains(null)) {
|
||||
return new TypedOperand(null, returnValue);
|
||||
} else {
|
||||
return new TypedOperand(f.perform(stringParameters), returnValue);
|
||||
}
|
||||
}
|
||||
|
||||
private List<String> getParametersAsString() throws ODataApplicationException {
|
||||
List<String> result = new ArrayList<String>();
|
||||
|
||||
for (VisitorOperand param : parameters) {
|
||||
TypedOperand operand = param.asTypedOperand();
|
||||
if (operand.isNull()) {
|
||||
result.add(null);
|
||||
} else if (operand.is(EdmString.getInstance())) {
|
||||
result.add(operand.getTypedValue(String.class));
|
||||
} else {
|
||||
throw new ODataApplicationException("Invalid parameter. Expected Edm.String", HttpStatusCode.BAD_REQUEST
|
||||
.getStatusCode(), Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.operation;
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.apache.olingo.commons.api.http.HttpStatusCode;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.EdmDuration;
|
||||
import org.apache.olingo.server.api.ODataApplicationException;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.TypedOperand;
|
||||
import org.apache.olingo.server.tecsvc.processor.expression.operand.VisitorOperand;
|
||||
|
||||
public class UnaryOperator {
|
||||
final private TypedOperand operand;
|
||||
|
||||
public UnaryOperator(VisitorOperand operand) throws ODataApplicationException {
|
||||
this.operand = operand.asTypedOperand();
|
||||
}
|
||||
|
||||
public VisitorOperand minusOperation() throws ODataApplicationException {
|
||||
if (operand.isNull()) {
|
||||
return operand;
|
||||
} else if (operand.isIntegerType()) {
|
||||
return new TypedOperand(operand.getTypedValue(BigInteger.class).negate(), operand.getType());
|
||||
} else if (operand.isDecimalType() || operand.is(EdmDuration.getInstance())) {
|
||||
return new TypedOperand(operand.getTypedValue(BigDecimal.class).negate(), operand.getType());
|
||||
} else {
|
||||
throw new ODataApplicationException("Unsupported type", HttpStatusCode.BAD_REQUEST.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
||||
|
||||
public VisitorOperand notOperation() throws ODataApplicationException {
|
||||
if (operand.isNull()) {
|
||||
return operand;
|
||||
} else if (operand.is(EdmBoolean.getInstance())) {
|
||||
return new TypedOperand(!operand.getTypedValue(Boolean.class), operand.getType());
|
||||
} else {
|
||||
throw new ODataApplicationException("Unsupported type", HttpStatusCode.BAD_REQUEST.getStatusCode(),
|
||||
Locale.ROOT);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.olingo.server.tecsvc.processor.expression.primitive;
|
||||
|
||||
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
|
||||
import org.apache.olingo.commons.core.edm.primitivetype.SingletonPrimitiveType;
|
||||
|
||||
|
||||
public final class EdmNull extends SingletonPrimitiveType {
|
||||
|
||||
private static final EdmNull instance = new EdmNull();
|
||||
|
||||
public static EdmNull getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getDefaultType() {
|
||||
return Object.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> T internalValueOfString(String value, Boolean isNullable, Integer maxLength, Integer precision,
|
||||
Integer scale, Boolean isUnicode, Class<T> returnType) throws EdmPrimitiveTypeException {
|
||||
if (!value.equals("null")) {
|
||||
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
|
||||
}
|
||||
|
||||
if (returnType.isAssignableFrom(Object.class)) {
|
||||
return returnType.cast(new Object());
|
||||
} else {
|
||||
throw new ClassCastException("unsupported return type " + returnType.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> String internalValueToString(T value, Boolean isNullable, Integer maxLength, Integer precision,
|
||||
Integer scale, Boolean isUnicode) throws EdmPrimitiveTypeException {
|
||||
return "null";
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue