[OLINGO-663] clean-up

Change-Id: Id1359ca3243e42d83ce0bd3057da3477850730e6

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Klaus Straubinger 2015-06-02 15:14:57 +02:00 committed by Christian Amend
parent a4913636dc
commit c65ef5e9e7
23 changed files with 463 additions and 278 deletions

View File

@ -212,8 +212,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase {
// Check initial next link format // Check initial next link format
URI nextLink = response.getBody().getNext(); URI nextLink = response.getBody().getNext();
assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24skiptoken=1", nextLink assertEquals(SERVICE_URI + "/ESServerSidePaging?%24skiptoken=1", nextLink.toASCIIString());
.toASCIIString());
// Check subsequent next links // Check subsequent next links
response = client.getRetrieveRequestFactory() response = client.getRetrieveRequestFactory()
@ -221,8 +220,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase {
.execute(); .execute();
nextLink = response.getBody().getNext(); nextLink = response.getBody().getNext();
assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24skiptoken=2", nextLink assertEquals(SERVICE_URI + "/ESServerSidePaging?%24skiptoken=2", nextLink.toASCIIString());
.toASCIIString());
} }
@Test @Test
@ -239,7 +237,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase {
// Check initial next link format // Check initial next link format
URI nextLink = response.getBody().getNext(); URI nextLink = response.getBody().getNext();
assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24count=true&%24skiptoken=1", assertEquals(SERVICE_URI + "/ESServerSidePaging?%24count=true&%24skiptoken=1",
nextLink.toASCIIString()); nextLink.toASCIIString());
int token = 1; int token = 1;
@ -253,9 +251,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase {
nextLink = response.getBody().getNext(); nextLink = response.getBody().getNext();
if (nextLink != null) { if (nextLink != null) {
assertEquals( assertEquals(SERVICE_URI + "/ESServerSidePaging?%24count=true&%24skiptoken=" + token,
"http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24count=true&%24skiptoken="
+ token,
nextLink.toASCIIString()); nextLink.toASCIIString());
} }
} }

View File

@ -1,29 +0,0 @@
/*
* 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.client.api.communication.response;
/**
* This interface defines the response to an OData link operation request.
*
* @see org.apache.olingo.client.api.communication.request.cud.v3.ODataLinkCreateRequest
* @see org.apache.olingo.client.api.communication.request.cud.v3.ODataLinkUpdateRequest
*/
public interface ODataLinkOperationResponse extends ODataResponse {
//No additional methods needed for now.
}

View File

@ -0,0 +1,74 @@
/*
* 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.api;
import java.util.Collection;
/**
* Information about the values of an ETag-relevant HTTP header.
*/
public class ETagInformation {
private final boolean all;
private final Collection<String> eTags;
public ETagInformation(final boolean all, final Collection<String> eTags) {
this.all = all;
this.eTags = eTags;
}
/**
* Gets the information whether the values contain "*".
*/
public boolean isAll() {
return all;
}
/**
* Gets the collection of ETag values found.
* It is empty if {@link #isAll()} returns <code>true</code>.
*/
public Collection<String> getETags() {
return eTags;
}
/**
* <p>Checks whether a given ETag value is matched by this ETag information,
* using weak comparison as described in
* <a href="https://www.ietf.org/rfc/rfc7232.txt">RFC 7232</a>, section 2.3.2.</p>
* <p>If the given value is <code>null</code>, or if this ETag information
* does not contain anything, the result is <code>false</code>.</p>
* @param eTag the ETag value to match
* @return a boolean match result
*/
public boolean isMatchedBy(final String eTag) {
if (eTag == null) {
return false;
} else if (all) {
return true;
} else {
for (final String candidate : eTags) {
if ((eTag.startsWith("W/") ? eTag.substring(2) : eTag)
.equals(candidate.startsWith("W/") ? candidate.substring(2) : candidate)) {
return true;
}
}
return false;
}
}
}

View File

@ -23,13 +23,13 @@ import java.util.Collection;
/** /**
* Information about the values of an ETag-relevant HTTP header. * Information about the values of an ETag-relevant HTTP header.
*/ */
public class EtagInformation { public class ETagInformation {
private final boolean all; private final boolean all;
private final Collection<String> etags; private final Collection<String> eTags;
public EtagInformation(final boolean all, final Collection<String> etags) { public ETagInformation(final boolean all, final Collection<String> eTags) {
this.all = all; this.all = all;
this.etags = etags; this.eTags = eTags;
} }
/** /**
@ -43,8 +43,8 @@ public class EtagInformation {
* Gets the collection of ETag values found. * Gets the collection of ETag values found.
* It is empty if {@link #isAll()} returns <code>true</code>. * It is empty if {@link #isAll()} returns <code>true</code>.
*/ */
public Collection<String> getEtags() { public Collection<String> getETags() {
return etags; return eTags;
} }
/** /**
@ -53,17 +53,17 @@ public class EtagInformation {
* <a href="https://www.ietf.org/rfc/rfc7232.txt">RFC 7232</a>, section 2.3.2.</p> * <a href="https://www.ietf.org/rfc/rfc7232.txt">RFC 7232</a>, section 2.3.2.</p>
* <p>If the given value is <code>null</code>, or if this ETag information * <p>If the given value is <code>null</code>, or if this ETag information
* does not contain anything, the result is <code>false</code>.</p> * does not contain anything, the result is <code>false</code>.</p>
* @param etag the ETag value to match * @param eTag the ETag value to match
* @return a boolean match result * @return a boolean match result
*/ */
public boolean isMatchedBy(final String etag) { public boolean isMatchedBy(final String eTag) {
if (etag == null) { if (eTag == null) {
return false; return false;
} else if (all) { } else if (all) {
return true; return true;
} else { } else {
for (final String candidate : etags) { for (final String candidate : eTags) {
if ((etag.startsWith("W/") ? etag.substring(2) : etag) if ((eTag.startsWith("W/") ? eTag.substring(2) : eTag)
.equals(candidate.startsWith("W/") ? candidate.substring(2) : candidate)) { .equals(candidate.startsWith("W/") ? candidate.substring(2) : candidate)) {
return true; return true;
} }

View File

@ -118,11 +118,11 @@ public abstract class OData {
public abstract EdmPrimitiveType createPrimitiveTypeInstance(EdmPrimitiveTypeKind kind); public abstract EdmPrimitiveType createPrimitiveTypeInstance(EdmPrimitiveTypeKind kind);
/** /**
* Creates Etag information from the values of a HTTP header * Creates ETag information from the values of a HTTP header
* containing a list of entity tags or a single star character, i.e., * containing a list of entity tags or a single star character, i.e.,
* <code>If-Match</code> and <code>If-None-Match</code>. * <code>If-Match</code> and <code>If-None-Match</code>.
* @param values the collection of header values * @param values the collection of header values
* @return an {@link EtagInformation} instance * @return an {@link ETagInformation} instance
*/ */
public abstract EtagInformation createEtagInformation(final Collection<String> values); public abstract ETagInformation createETagInformation(final Collection<String> values);
} }

View File

@ -0,0 +1,86 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <p>Parses the values of HTTP header fields that contain a list of entity tags or a
* single star character, i.e., <code>If-Match</code> and <code>If-None-Match</code>.</p>
* <p>See <a href="https://www.ietf.org/rfc/rfc7232.txt">RFC 7232</a> for details;
* there the following grammar is defined:</p>
* <pre>
* If-Match = "*" / 1#entity-tag
* If-None-Match = "*" / 1#entity-tag
* entity-tag = [ weak ] opaque-tag
* weak = %x57.2F ; "W/", case-sensitive
* opaque-tag = DQUOTE *etagc DQUOTE
* etagc = %x21 / %x23-7E / %x80-FF
* </pre>
* <p>Values with illegal syntax do not contribute to the result but no exception is thrown.</p>
*/
public class ETagParser {
private static final Pattern ETAG = Pattern.compile("\\s*(,\\s*)+|((?:W/)?\"[!#-~\\x80-\\xFF]*\")");
protected static Collection<String> parse(final Collection<String> values) {
if (values == null) {
return Collections.<String> emptySet();
}
Set<String> result = new HashSet<String>();
for (final String value : values) {
final Collection<String> part = parse(value);
if (part.size() == 1 && part.iterator().next().equals("*")) {
return part;
} else {
result.addAll(part);
}
}
return result;
}
private static Collection<String> parse(final String value) {
if (value.trim().equals("*")) {
return Collections.singleton("*");
} else {
Set<String> result = new HashSet<String>();
String separator = "";
int start = 0;
Matcher matcher = ETAG.matcher(value.trim());
while (matcher.find() && matcher.start() == start) {
start = matcher.end();
if (matcher.group(1) != null) {
separator = matcher.group(1);
} else if (separator != null) {
result.add(matcher.group(2));
separator = null;
} else {
return Collections.<String> emptySet();
}
}
return matcher.hitEnd() ? result : Collections.<String> emptySet();
}
}
}

View File

@ -40,7 +40,7 @@ import java.util.regex.Pattern;
* </pre> * </pre>
* <p>Values with illegal syntax do not contribute to the result but no exception is thrown.</p> * <p>Values with illegal syntax do not contribute to the result but no exception is thrown.</p>
*/ */
public class EtagParser { public class ETagParser {
private static final Pattern ETAG = Pattern.compile("\\s*(,\\s*)+|((?:W/)?\"[!#-~\\x80-\\xFF]*\")"); private static final Pattern ETAG = Pattern.compile("\\s*(,\\s*)+|((?:W/)?\"[!#-~\\x80-\\xFF]*\")");

View File

@ -27,7 +27,7 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider; import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider;
import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.format.ODataFormat;
import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
import org.apache.olingo.server.api.EtagInformation; import org.apache.olingo.server.api.ETagInformation;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataHttpHandler; import org.apache.olingo.server.api.ODataHttpHandler;
import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.ServiceMetadata;
@ -119,10 +119,10 @@ public class ODataImpl extends OData {
} }
@Override @Override
public EtagInformation createEtagInformation(final Collection<String> values) { public ETagInformation createETagInformation(final Collection<String> values) {
final Collection<String> etags = EtagParser.parse(values); final Collection<String> eTags = ETagParser.parse(values);
final boolean isAll = etags.size() == 1 && etags.iterator().next().equals("*"); final boolean isAll = eTags.size() == 1 && eTags.iterator().next().equals("*");
return new EtagInformation(isAll, return new ETagInformation(isAll,
isAll ? Collections.<String> emptySet() : Collections.unmodifiableCollection(etags)); isAll ? Collections.<String> emptySet() : Collections.unmodifiableCollection(eTags));
} }
} }

View File

@ -24,7 +24,9 @@ public class PreconditionRequiredException extends ODataTranslatedException {
private static final long serialVersionUID = -8112658467394158700L; private static final long serialVersionUID = -8112658467394158700L;
public static enum MessageKeys implements MessageKey { public static enum MessageKeys implements MessageKey {
/** no parameter */
MISSING_HEADER, MISSING_HEADER,
/** no parameter */
INVALID_URI; INVALID_URI;
@Override @Override
@ -39,8 +41,7 @@ public class PreconditionRequiredException extends ODataTranslatedException {
} }
public PreconditionRequiredException(final String developmentMessage, final Throwable cause, public PreconditionRequiredException(final String developmentMessage, final Throwable cause,
final MessageKey messageKey, final MessageKey messageKey, final String... parameters) {
final String... parameters) {
super(developmentMessage, cause, messageKey, parameters); super(developmentMessage, cause, messageKey, parameters);
} }

View File

@ -28,10 +28,10 @@ import org.apache.olingo.server.api.processor.BatchProcessor;
import org.apache.olingo.server.core.ODataHandler; import org.apache.olingo.server.core.ODataHandler;
import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon; import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
public class BatchFascadeImpl implements BatchFacade { public class BatchFacadeImpl implements BatchFacade {
private final BatchPartHandler partHandler; private final BatchPartHandler partHandler;
public BatchFascadeImpl(final ODataHandler oDataHandler, final ODataRequest request, public BatchFacadeImpl(final ODataHandler oDataHandler, final ODataRequest request,
final BatchProcessor batchProcessor, final BatchProcessor batchProcessor,
final boolean isStrict) { final boolean isStrict) {
partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this); partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this);

View File

@ -45,7 +45,7 @@ public class BatchHandler {
throws DeserializerException, SerializerException { throws DeserializerException, SerializerException {
validateRequest(request); validateRequest(request);
final BatchFacade operation = new BatchFascadeImpl(oDataHandler, request, batchProcessor, isStrict); final BatchFacade operation = new BatchFacadeImpl(oDataHandler, request, batchProcessor, isStrict);
batchProcessor.processBatch(operation, request, response); batchProcessor.processBatch(operation, request, response);
} }

View File

@ -0,0 +1,131 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.olingo.server.core;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.hasItems;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import org.apache.olingo.server.api.ETagInformation;
import org.apache.olingo.server.api.OData;
import org.junit.Test;
public class ETagParserTest {
private static final OData odata = OData.newInstance();
@Test
public void empty() {
final ETagInformation eTagInformation = odata.createETagInformation(null);
assertFalse(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertTrue(eTagInformation.getETags().isEmpty());
}
@Test
public void loneStar() {
final ETagInformation eTagInformation = odata.createETagInformation(Collections.singleton("*"));
assertTrue(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertTrue(eTagInformation.getETags().isEmpty());
}
@Test
public void starWins() {
final ETagInformation eTagInformation = odata.createETagInformation(Arrays.asList("\"ETag\"", "*"));
assertTrue(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertTrue(eTagInformation.getETags().isEmpty());
}
@Test
public void starAsEtagAndEmptyEtag() {
final ETagInformation eTagInformation = odata.createETagInformation(
Collections.singleton("\"*\", \"\""));
assertFalse(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertThat(eTagInformation.getETags().size(), equalTo(2));
assertThat(eTagInformation.getETags(), hasItems("\"*\"", "\"\""));
}
@Test
public void severalEtags() {
final ETagInformation eTagInformation = odata.createETagInformation(
Arrays.asList("\"ETag1\"", "\"ETag2\",, , ,W/\"ETag3\", ,"));
assertFalse(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertThat(eTagInformation.getETags().size(), equalTo(3));
assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag3\""));
}
@Test
public void duplicateEtagValues() {
final ETagInformation eTagInformation = odata.createETagInformation(
Arrays.asList("\"ETag1\"", "\"ETag2\", W/\"ETag1\", \"ETag1\""));
assertFalse(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertThat(eTagInformation.getETags().size(), equalTo(3));
assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag1\""));
}
@Test
public void specialCharacters() {
final ETagInformation eTagInformation = odata.createETagInformation(
Collections.singleton("\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\", \"ETag2\""));
assertFalse(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertThat(eTagInformation.getETags().size(), equalTo(2));
assertThat(eTagInformation.getETags(), hasItems(
"\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\"", "\"ETag2\""));
}
@Test
public void wrongFormat() {
final ETagInformation eTagInformation = odata.createETagInformation(
Arrays.asList("\"ETag1\", ETag2", "w/\"ETag3\"", "W//\"ETag4\"", "W/ETag5",
"\"\"ETag6\"\"", " \"ETag7\"\"ETag7\" ", "\"ETag8\" \"ETag8\"",
"\"ETag 9\"", "\"ETag10\""));
assertFalse(eTagInformation.isAll());
assertNotNull(eTagInformation.getETags());
assertThat(eTagInformation.getETags().size(), equalTo(2));
assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag10\""));
}
@Test
public void match() {
assertFalse(odata.createETagInformation(Collections.<String> emptySet()).isMatchedBy("\"ETag\""));
assertFalse(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy(null));
assertTrue(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("\"ETag\""));
assertTrue(odata.createETagInformation(Collections.singleton("*")).isMatchedBy("\"ETag\""));
assertTrue(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag\""));
assertTrue(odata.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag\""));
assertFalse(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag2\""));
assertFalse(odata.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag2\""));
assertTrue(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\""))
.isMatchedBy("\"ETag4\""));
assertFalse(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\""))
.isMatchedBy("\"ETag5\""));
}
}

View File

@ -28,104 +28,104 @@ import static org.junit.Assert.assertTrue;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import org.apache.olingo.server.api.EtagInformation; import org.apache.olingo.server.api.ETagInformation;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.junit.Test; import org.junit.Test;
public class EtagParserTest { public class ETagParserTest {
private static final OData odata = OData.newInstance(); private static final OData odata = OData.newInstance();
@Test @Test
public void empty() { public void empty() {
final EtagInformation etagInformation = odata.createEtagInformation(null); final ETagInformation eTagInformation = odata.createETagInformation(null);
assertFalse(etagInformation.isAll()); assertFalse(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertTrue(etagInformation.getEtags().isEmpty()); assertTrue(eTagInformation.getETags().isEmpty());
} }
@Test @Test
public void loneStar() { public void loneStar() {
final EtagInformation etagInformation = odata.createEtagInformation(Collections.singleton("*")); final ETagInformation eTagInformation = odata.createETagInformation(Collections.singleton("*"));
assertTrue(etagInformation.isAll()); assertTrue(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertTrue(etagInformation.getEtags().isEmpty()); assertTrue(eTagInformation.getETags().isEmpty());
} }
@Test @Test
public void starWins() { public void starWins() {
final EtagInformation etagInformation = odata.createEtagInformation(Arrays.asList("\"ETag\"", "*")); final ETagInformation eTagInformation = odata.createETagInformation(Arrays.asList("\"ETag\"", "*"));
assertTrue(etagInformation.isAll()); assertTrue(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertTrue(etagInformation.getEtags().isEmpty()); assertTrue(eTagInformation.getETags().isEmpty());
} }
@Test @Test
public void starAsEtagAndEmptyEtag() { public void starAsEtagAndEmptyEtag() {
final EtagInformation etagInformation = odata.createEtagInformation( final ETagInformation eTagInformation = odata.createETagInformation(
Collections.singleton("\"*\", \"\"")); Collections.singleton("\"*\", \"\""));
assertFalse(etagInformation.isAll()); assertFalse(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertThat(etagInformation.getEtags().size(), equalTo(2)); assertThat(eTagInformation.getETags().size(), equalTo(2));
assertThat(etagInformation.getEtags(), hasItems("\"*\"", "\"\"")); assertThat(eTagInformation.getETags(), hasItems("\"*\"", "\"\""));
} }
@Test @Test
public void severalEtags() { public void severalEtags() {
final EtagInformation etagInformation = odata.createEtagInformation( final ETagInformation eTagInformation = odata.createETagInformation(
Arrays.asList("\"ETag1\"", "\"ETag2\",, , ,W/\"ETag3\", ,")); Arrays.asList("\"ETag1\"", "\"ETag2\",, , ,W/\"ETag3\", ,"));
assertFalse(etagInformation.isAll()); assertFalse(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertThat(etagInformation.getEtags().size(), equalTo(3)); assertThat(eTagInformation.getETags().size(), equalTo(3));
assertThat(etagInformation.getEtags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag3\"")); assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag3\""));
} }
@Test @Test
public void duplicateEtagValues() { public void duplicateEtagValues() {
final EtagInformation etagInformation = odata.createEtagInformation( final ETagInformation eTagInformation = odata.createETagInformation(
Arrays.asList("\"ETag1\"", "\"ETag2\", W/\"ETag1\", \"ETag1\"")); Arrays.asList("\"ETag1\"", "\"ETag2\", W/\"ETag1\", \"ETag1\""));
assertFalse(etagInformation.isAll()); assertFalse(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertThat(etagInformation.getEtags().size(), equalTo(3)); assertThat(eTagInformation.getETags().size(), equalTo(3));
assertThat(etagInformation.getEtags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag1\"")); assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag1\""));
} }
@Test @Test
public void specialCharacters() { public void specialCharacters() {
final EtagInformation etagInformation = odata.createEtagInformation( final ETagInformation eTagInformation = odata.createETagInformation(
Collections.singleton("\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\", \"ETag2\"")); Collections.singleton("\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\", \"ETag2\""));
assertFalse(etagInformation.isAll()); assertFalse(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertThat(etagInformation.getEtags().size(), equalTo(2)); assertThat(eTagInformation.getETags().size(), equalTo(2));
assertThat(etagInformation.getEtags(), hasItems( assertThat(eTagInformation.getETags(), hasItems(
"\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\"", "\"ETag2\"")); "\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\"", "\"ETag2\""));
} }
@Test @Test
public void wrongFormat() { public void wrongFormat() {
final EtagInformation etagInformation = odata.createEtagInformation( final ETagInformation eTagInformation = odata.createETagInformation(
Arrays.asList("\"ETag1\", ETag2", "w/\"ETag3\"", "W//\"ETag4\"", "W/ETag5", Arrays.asList("\"ETag1\", ETag2", "w/\"ETag3\"", "W//\"ETag4\"", "W/ETag5",
"\"\"ETag6\"\"", " \"ETag7\"\"ETag7\" ", "\"ETag8\" \"ETag8\"", "\"\"ETag6\"\"", " \"ETag7\"\"ETag7\" ", "\"ETag8\" \"ETag8\"",
"\"ETag 9\"", "\"ETag10\"")); "\"ETag 9\"", "\"ETag10\""));
assertFalse(etagInformation.isAll()); assertFalse(eTagInformation.isAll());
assertNotNull(etagInformation.getEtags()); assertNotNull(eTagInformation.getETags());
assertThat(etagInformation.getEtags().size(), equalTo(2)); assertThat(eTagInformation.getETags().size(), equalTo(2));
assertThat(etagInformation.getEtags(), hasItems("\"ETag1\"", "\"ETag10\"")); assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag10\""));
} }
@Test @Test
public void match() { public void match() {
assertFalse(odata.createEtagInformation(Collections.<String> emptySet()).isMatchedBy("\"ETag\"")); assertFalse(odata.createETagInformation(Collections.<String> emptySet()).isMatchedBy("\"ETag\""));
assertFalse(odata.createEtagInformation(Collections.singleton("\"ETag\"")).isMatchedBy(null)); assertFalse(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy(null));
assertTrue(odata.createEtagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("\"ETag\"")); assertTrue(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("\"ETag\""));
assertTrue(odata.createEtagInformation(Collections.singleton("*")).isMatchedBy("\"ETag\"")); assertTrue(odata.createETagInformation(Collections.singleton("*")).isMatchedBy("\"ETag\""));
assertTrue(odata.createEtagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag\"")); assertTrue(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag\""));
assertTrue(odata.createEtagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag\"")); assertTrue(odata.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag\""));
assertFalse(odata.createEtagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag2\"")); assertFalse(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag2\""));
assertFalse(odata.createEtagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag2\"")); assertFalse(odata.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag2\""));
assertTrue(odata.createEtagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) assertTrue(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\""))
.isMatchedBy("\"ETag4\"")); .isMatchedBy("\"ETag4\""));
assertFalse(odata.createEtagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) assertFalse(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\""))
.isMatchedBy("\"ETag5\"")); .isMatchedBy("\"ETag5\""));
} }
} }

View File

@ -579,7 +579,7 @@ public class DataProvider {
} }
} }
private Entity getEntityByReference(final String entityId, final String rawServiceRoot) protected Entity getEntityByReference(final String entityId, final String rawServiceRoot)
throws DataProviderException { throws DataProviderException {
try { try {
final UriResourceEntitySet uriResource = odata.createUriHelper().parseEntityId(edm, entityId, rawServiceRoot); final UriResourceEntitySet uriResource = odata.createUriHelper().parseEntityId(edm, entityId, rawServiceRoot);
@ -603,7 +603,7 @@ public class DataProvider {
} }
public DataProviderException(final String message) { public DataProviderException(final String message) {
super(message, HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); this(message, HttpStatusCode.INTERNAL_SERVER_ERROR);
} }
public DataProviderException(final String message, final HttpStatusCode statusCode) { public DataProviderException(final String message, final HttpStatusCode statusCode) {

View File

@ -27,7 +27,6 @@ import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Link;
import org.apache.olingo.commons.api.data.Linked; import org.apache.olingo.commons.api.data.Linked;
import org.apache.olingo.commons.api.data.Property; import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.edm.Edm;
import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmBindingTarget;
import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmComplexType;
import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmEntityType;
@ -35,35 +34,23 @@ import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmStructuredType; import org.apache.olingo.commons.api.edm.EdmStructuredType;
import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.deserializer.DeserializerException;
import org.apache.olingo.server.api.uri.UriHelper;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;
import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException; import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException;
public class RequestValidator { public class RequestValidator {
private DataProvider provider; private final DataProvider provider;
private boolean isInsert; private final boolean isInsert;
private boolean isPatch; private final boolean isPatch;
private UriHelper uriHelper; private final String rawServiceRoot;
private Edm edm;
private String rawServiceRoot;
public RequestValidator(final DataProvider provider, final UriHelper uriHelper, public RequestValidator(final DataProvider provider, final String rawServiceRoot) {
final Edm edm, final String rawServiceRoot) { this(provider, false, false, rawServiceRoot);
this.provider = provider;
isInsert = true;
this.uriHelper = uriHelper;
this.edm = edm;
this.rawServiceRoot = rawServiceRoot;
} }
public RequestValidator(final DataProvider provider, final boolean isUpdate, final boolean isPatch, public RequestValidator(final DataProvider provider, final boolean isUpdate, final boolean isPatch,
final UriHelper uriHelper, final Edm edm, final String rawServiceRoot) { final String rawServiceRoot) {
this.provider = provider; this.provider = provider;
isInsert = !isUpdate; this.isInsert = !isUpdate;
this.isPatch = isPatch; this.isPatch = isPatch;
this.uriHelper = uriHelper;
this.edm = edm;
this.rawServiceRoot = rawServiceRoot; this.rawServiceRoot = rawServiceRoot;
} }
@ -89,15 +76,15 @@ public class RequestValidator {
newPath.add(edmProperty.getName()); newPath.add(edmProperty.getName());
final EdmBindingTarget target = edmBindingTarget.getRelatedBindingTarget(buildPath(newPath)); final EdmBindingTarget target = edmBindingTarget.getRelatedBindingTarget(buildPath(newPath));
final ValidatioResult bindingResult = validateBinding(navigationBinding, edmProperty, target); final ValidationResult bindingResult = validateBinding(navigationBinding, edmProperty);
final ValidatioResult linkResult = validateNavigationLink(navigationLink, final ValidationResult linkResult = validateNavigationLink(navigationLink,
edmProperty, edmProperty,
target); target);
if ((isInsert && !edmProperty.isNullable() if ((isInsert && !edmProperty.isNullable()
&& (bindingResult != ValidatioResult.FOUND && (bindingResult != ValidationResult.FOUND
&& linkResult != ValidatioResult.FOUND)) && linkResult != ValidationResult.FOUND))
|| (!(isInsert && isPatch) && !edmProperty.isNullable() && linkResult == ValidatioResult.EMPTY)) { || (!(isInsert && isPatch) && !edmProperty.isNullable() && linkResult == ValidationResult.EMPTY)) {
throw new DataProviderException("Navigation property " + navPropertyName + " must not be null", throw new DataProviderException("Navigation property " + navPropertyName + " must not be null",
HttpStatusCode.BAD_REQUEST); HttpStatusCode.BAD_REQUEST);
} }
@ -119,35 +106,35 @@ public class RequestValidator {
return builder.toString(); return builder.toString();
} }
private ValidatioResult validateBinding(final Link navigationBindung, final EdmNavigationProperty edmProperty, private ValidationResult validateBinding(final Link navigationBinding, final EdmNavigationProperty edmProperty)
final EdmBindingTarget edmBindingTarget) throws DataProviderException { throws DataProviderException {
if (navigationBindung == null) { if (navigationBinding == null) {
return ValidatioResult.NOT_FOUND; return ValidationResult.NOT_FOUND;
} }
if (edmProperty.isCollection()) { if (edmProperty.isCollection()) {
if (navigationBindung.getBindingLinks().size() == 0) { if (navigationBinding.getBindingLinks().size() == 0) {
return ValidatioResult.EMPTY; return ValidationResult.EMPTY;
} }
for (final String bindingLink : navigationBindung.getBindingLinks()) { for (final String bindingLink : navigationBinding.getBindingLinks()) {
validateLink(bindingLink, edmBindingTarget); validateLink(bindingLink);
} }
} else { } else {
if (navigationBindung.getBindingLink() == null) { if (navigationBinding.getBindingLink() == null) {
return ValidatioResult.EMPTY; return ValidationResult.EMPTY;
} }
validateLink(navigationBindung.getBindingLink(), edmBindingTarget); validateLink(navigationBinding.getBindingLink());
} }
return ValidatioResult.FOUND; return ValidationResult.FOUND;
} }
private ValidatioResult validateNavigationLink(final Link navigationLink, final EdmNavigationProperty edmProperty, private ValidationResult validateNavigationLink(final Link navigationLink, final EdmNavigationProperty edmProperty,
final EdmBindingTarget edmBindingTarget) throws DataProviderException { final EdmBindingTarget edmBindingTarget) throws DataProviderException {
if (navigationLink == null) { if (navigationLink == null) {
return ValidatioResult.NOT_FOUND; return ValidationResult.NOT_FOUND;
} }
if (edmProperty.isCollection()) { if (edmProperty.isCollection()) {
@ -168,21 +155,11 @@ public class RequestValidator {
} }
} }
return ValidatioResult.FOUND; return ValidationResult.FOUND;
} }
private void validateLink(final String bindingLink, final EdmBindingTarget edmBindungTarget) private void validateLink(final String bindingLink) throws DataProviderException {
throws DataProviderException { provider.getEntityByReference(bindingLink, rawServiceRoot);
try {
final UriResourceEntitySet uriInfo = uriHelper.parseEntityId(edm, bindingLink, rawServiceRoot);
final Entity entity = provider.read(uriInfo.getEntitySet(), uriInfo.getKeyPredicates());
if (entity == null) {
throw new DataProviderException("Entity not found", HttpStatusCode.NOT_FOUND);
}
} catch (DeserializerException e) {
throw new DataProviderException("Invalid binding link", HttpStatusCode.BAD_REQUEST);
}
} }
private void validateEntitySetProperties(final List<Property> properties, final EdmBindingTarget edmBindingTarget, private void validateEntitySetProperties(final List<Property> properties, final EdmBindingTarget edmBindingTarget,
@ -190,7 +167,7 @@ public class RequestValidator {
validateProperties(properties, edmBindingTarget, edmType, edmType.getKeyPredicateNames(), path); validateProperties(properties, edmBindingTarget, edmType, edmType.getKeyPredicateNames(), path);
} }
private void validateProperties(final List<Property> properties, final EdmBindingTarget edmBingingTarget, private void validateProperties(final List<Property> properties, final EdmBindingTarget edmBindingTarget,
final EdmStructuredType edmType, final List<String> keyPredicateNames, final List<String> path) final EdmStructuredType edmType, final List<String> keyPredicateNames, final List<String> path)
throws DataProviderException { throws DataProviderException {
@ -212,7 +189,7 @@ public class RequestValidator {
} }
// Validate property value // Validate property value
validatePropertyValue(property, edmProperty, edmBingingTarget, path); validatePropertyValue(property, edmProperty, edmBindingTarget, path);
} }
} }
} }
@ -259,7 +236,7 @@ public class RequestValidator {
return null; return null;
} }
private static enum ValidatioResult { private static enum ValidationResult {
FOUND, FOUND,
NOT_FOUND, NOT_FOUND,
EMPTY EMPTY

View File

@ -159,10 +159,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
final DeserializerResult deserializerResult = final DeserializerResult deserializerResult =
odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) odata.createDeserializer(ODataFormat.fromContentType(requestFormat))
.entity(request.getBody(), edmEntityType); .entity(request.getBody(), edmEntityType);
new RequestValidator(dataProvider, new RequestValidator(dataProvider, request.getRawBaseUri())
odata.createUriHelper(), .validate(edmEntitySet, deserializerResult.getEntity());
serviceMetadata.getEdm(),
request.getRawBaseUri()).validate(edmEntitySet, deserializerResult.getEntity());
entity = dataProvider.create(edmEntitySet); entity = dataProvider.create(edmEntitySet);
dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false, dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false,
@ -213,8 +211,6 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
new RequestValidator(dataProvider, new RequestValidator(dataProvider,
true, // Update true, // Update
request.getMethod() == HttpMethod.PATCH, request.getMethod() == HttpMethod.PATCH,
odata.createUriHelper(),
serviceMetadata.getEdm(),
request.getRawBaseUri()).validate(edmEntitySet, changedEntity); request.getRawBaseUri()).validate(edmEntitySet, changedEntity);
dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity, dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity,

View File

@ -32,7 +32,7 @@ import org.apache.olingo.commons.api.edm.EdmFunction;
import org.apache.olingo.commons.api.edm.EdmNavigationProperty; import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.EtagInformation; import org.apache.olingo.server.api.ETagInformation;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.ServiceMetadata;
@ -262,12 +262,12 @@ public abstract class TechnicalProcessor implements Processor {
final Collection<String> ifMatchHeaders, final Collection<String> ifNoneMatchHeaders) final Collection<String> ifMatchHeaders, final Collection<String> ifNoneMatchHeaders)
throws ODataApplicationException { throws ODataApplicationException {
if (eTag != null) { if (eTag != null) {
final EtagInformation ifMatch = odata.createEtagInformation(ifMatchHeaders); final ETagInformation ifMatch = odata.createETagInformation(ifMatchHeaders);
if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getEtags().isEmpty()) { if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getETags().isEmpty()) {
throw new ODataApplicationException("The If-Match precondition is not fulfilled.", throw new ODataApplicationException("The If-Match precondition is not fulfilled.",
HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT); HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT);
} }
if (odata.createEtagInformation(ifNoneMatchHeaders).isMatchedBy(eTag)) { if (odata.createETagInformation(ifNoneMatchHeaders).isMatchedBy(eTag)) {
throw new ODataApplicationException("The entity has not been modified.", throw new ODataApplicationException("The entity has not been modified.",
HttpStatusCode.NOT_MODIFIED.getStatusCode(), Locale.ROOT); HttpStatusCode.NOT_MODIFIED.getStatusCode(), Locale.ROOT);
} }
@ -278,9 +278,9 @@ public abstract class TechnicalProcessor implements Processor {
final Collection<String> ifMatchHeaders, final Collection<String> ifNoneMatchHeaders) final Collection<String> ifMatchHeaders, final Collection<String> ifNoneMatchHeaders)
throws ODataApplicationException { throws ODataApplicationException {
if (eTag != null) { if (eTag != null) {
final EtagInformation ifMatch = odata.createEtagInformation(ifMatchHeaders); final ETagInformation ifMatch = odata.createETagInformation(ifMatchHeaders);
final EtagInformation ifNoneMatch = odata.createEtagInformation(ifNoneMatchHeaders); final ETagInformation ifNoneMatch = odata.createETagInformation(ifNoneMatchHeaders);
if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getEtags().isEmpty() if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getETags().isEmpty()
|| ifNoneMatch.isMatchedBy(eTag)) { || ifNoneMatch.isMatchedBy(eTag)) {
throw new ODataApplicationException("The preconditions are not fulfilled.", throw new ODataApplicationException("The preconditions are not fulfilled.",
HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT); HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT);

View File

@ -27,7 +27,6 @@ import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public class TypedOperand extends VisitorOperand { public class TypedOperand extends VisitorOperand {
@ -56,7 +55,7 @@ public class TypedOperand extends VisitorOperand {
@Override @Override
public TypedOperand asTypedOperand(final EdmPrimitiveType... asTypes) throws ODataApplicationException { public TypedOperand asTypedOperand(final EdmPrimitiveType... asTypes) throws ODataApplicationException {
if (type.equals(EdmNull.getInstance())) { if (is(primNull)) {
return this; return this;
} else if (isNull()) { } else if (isNull()) {
return new TypedOperand(null, asTypes[0]); return new TypedOperand(null, asTypes[0]);
@ -103,7 +102,7 @@ public class TypedOperand extends VisitorOperand {
if (type == oType && value != null && other.getValue() != null if (type == oType && value != null && other.getValue() != null
&& value.getClass() == other.getValue().getClass()) { && value.getClass() == other.getValue().getClass()) {
return this; return this;
} else if (isNullLiteral() || other.isNullLiteral()) { } else if (is(primNull) || other.is(primNull)) {
return this; return this;
} }
@ -132,16 +131,12 @@ public class TypedOperand extends VisitorOperand {
return clazz.cast(value); return clazz.cast(value);
} }
public boolean isNullLiteral() {
return type.equals(EdmNull.getInstance());
}
public boolean isNull() { public boolean isNull() {
return isNullLiteral() || value == null; return is(primNull) || value == null;
} }
public boolean isIntegerType() { public boolean isIntegerType() {
return is( return is(primNull,
primByte, primByte,
primSByte, primSByte,
primInt16, primInt16,
@ -150,23 +145,18 @@ public class TypedOperand extends VisitorOperand {
} }
public boolean isDecimalType() { public boolean isDecimalType() {
return is( return is(primNull,
primSingle, primSingle,
primDouble, primDouble,
primDecimal); primDecimal);
} }
public boolean is(final EdmPrimitiveType... types) { public boolean is(final EdmPrimitiveType... types) {
if (isNullLiteral()) {
return true;
}
for (EdmPrimitiveType type : types) { for (EdmPrimitiveType type : types) {
if (type.equals(this.type)) { if (type.equals(this.type)) {
return true; return true;
} }
} }
return false; return false;
} }

View File

@ -24,7 +24,6 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public class UntypedOperand extends VisitorOperand { public class UntypedOperand extends VisitorOperand {
@ -43,8 +42,8 @@ public class UntypedOperand extends VisitorOperand {
Object newValue = null; Object newValue = null;
// First try the null literal // First try the null literal
if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) { if ((newValue = tryCast(literal, primNull)) != null) {
return new TypedOperand(newValue, EdmNull.getInstance()); return new TypedOperand(newValue, primNull);
} }
// Than try the given types // Than try the given types
@ -65,8 +64,8 @@ public class UntypedOperand extends VisitorOperand {
Object newValue = null; Object newValue = null;
// Null literal // Null literal
if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) { if (primNull.validate(literal, null, null, null, null, null)) {
return new TypedOperand(newValue, EdmNull.getInstance()); return new TypedOperand(newValue, primNull);
} }
// String // String

View File

@ -29,11 +29,13 @@ import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public abstract class VisitorOperand { public abstract class VisitorOperand {
final static private HashMap<EdmType, Class<?>> defaultTypeMapping = new HashMap<EdmType, Class<?>>(); final static private HashMap<EdmType, Class<?>> defaultTypeMapping = new HashMap<EdmType, Class<?>>();
protected Object value; protected Object value;
protected static final OData oData; protected static final OData oData;
protected static final EdmPrimitiveType primNull = EdmNull.getInstance();
protected static final EdmPrimitiveType primString; protected static final EdmPrimitiveType primString;
protected static final EdmPrimitiveType primBoolean; protected static final EdmPrimitiveType primBoolean;
protected static final EdmPrimitiveType primDateTimeOffset; protected static final EdmPrimitiveType primDateTimeOffset;

View File

@ -37,6 +37,7 @@ import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand; import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand; import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand;
import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull;
public class MethodCallOperator { public class MethodCallOperator {
@ -317,8 +318,10 @@ public class MethodCallOperator {
throws ODataApplicationException { throws ODataApplicationException {
final TypedOperand operand = parameters.get(0).asTypedOperand(); final TypedOperand operand = parameters.get(0).asTypedOperand();
if (operand.isNull()) {
return new TypedOperand(null, EdmNull.getInstance());
} else {
if (operand.is(expectedTypes)) { if (operand.is(expectedTypes)) {
if (!operand.isNull()) {
Calendar calendar = null; Calendar calendar = null;
if (operand.is(primDate)) { if (operand.is(primDate)) {
calendar = operand.getTypedValue(Calendar.class); calendar = operand.getTypedValue(Calendar.class);
@ -331,21 +334,18 @@ public class MethodCallOperator {
} else { } else {
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
} }
return new TypedOperand(f.perform(calendar, operand), returnType); return new TypedOperand(f.perform(calendar, operand), returnType);
} else {
return new TypedOperand(null, returnType);
}
} else { } else {
throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);
} }
} }
}
private VisitorOperand stringFunction(final StringFunction f, final EdmType returnValue) private VisitorOperand stringFunction(final StringFunction f, final EdmType returnValue)
throws ODataApplicationException { throws ODataApplicationException {
List<String> stringParameters = getParametersAsString(); List<String> stringParameters = getParametersAsString();
if (stringParameters.contains(null)) { if (stringParameters.contains(null)) {
return new TypedOperand(null, returnValue); return new TypedOperand(null, EdmNull.getInstance());
} else { } else {
return new TypedOperand(f.perform(stringParameters), returnValue); return new TypedOperand(f.perform(stringParameters), returnValue);
} }

View File

@ -31,15 +31,26 @@ public final class EdmNull implements EdmPrimitiveType {
return instance; return instance;
} }
@Override
public String getNamespace() {
return EDM_NAMESPACE;
}
@Override
public String getName() {
return getClass().getSimpleName().substring(3);
}
@Override
public EdmTypeKind getKind() {
return EdmTypeKind.PRIMITIVE;
}
@Override @Override
public Class<?> getDefaultType() { public Class<?> getDefaultType() {
return Object.class; return Object.class;
} }
protected String uriPrefix = "";
protected String uriSuffix = "";
@Override @Override
public FullQualifiedName getFullQualifiedName() { public FullQualifiedName getFullQualifiedName() {
return new FullQualifiedName(getNamespace(), getName()); return new FullQualifiedName(getNamespace(), getName());
@ -54,13 +65,8 @@ public final class EdmNull implements EdmPrimitiveType {
public boolean validate(final String value, public boolean validate(final String value,
final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
final Boolean isUnicode) { final Boolean isUnicode) {
return value == null && (isNullable == null || isNullable)
try { || value.equals("null");
valueOfString(value, isNullable, maxLength, precision, scale, isUnicode, getDefaultType());
return true;
} catch (final EdmPrimitiveTypeException e) {
return false;
}
} }
@Override @Override
@ -68,14 +74,17 @@ public final class EdmNull implements EdmPrimitiveType {
final Boolean isNullable, final Integer maxLength, final Integer precision, final Boolean isNullable, final Integer maxLength, final Integer precision,
final Integer scale, final Boolean isUnicode, final Class<T> returnType) final Integer scale, final Boolean isUnicode, final Class<T> returnType)
throws EdmPrimitiveTypeException { throws EdmPrimitiveTypeException {
if (value == null) { if (value == null) {
if (isNullable != null && !isNullable) { if (isNullable != null && !isNullable) {
throw new EdmPrimitiveTypeException("The literal 'null' is not allowed."); throw new EdmPrimitiveTypeException("The literal 'null' is not allowed.");
} }
return null; return null;
} }
return internalValueOfString(value, isNullable, maxLength, precision, scale, isUnicode, returnType); if (value.equals("null")) {
return null;
} else {
throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content.");
}
} }
@Override @Override
@ -88,28 +97,17 @@ public final class EdmNull implements EdmPrimitiveType {
} }
return null; return null;
} }
return internalValueToString(value, isNullable, maxLength, precision, scale, isUnicode); return "null";
} }
@Override @Override
public String toUriLiteral(final String literal) { public String toUriLiteral(final String literal) {
return literal == null ? null : return literal == null ? null : literal;
uriPrefix.isEmpty() && uriSuffix.isEmpty() ? literal : uriPrefix + literal + uriSuffix;
} }
@Override @Override
public String fromUriLiteral(final String literal) throws EdmPrimitiveTypeException { public String fromUriLiteral(final String literal) throws EdmPrimitiveTypeException {
if (literal == null) { return literal == null ? null : literal;
return null;
} else if (uriPrefix.isEmpty() && uriSuffix.isEmpty()) {
return literal;
} else if (literal.length() >= uriPrefix.length() + uriSuffix.length()
&& literal.startsWith(uriPrefix) && literal.endsWith(uriSuffix)) {
return literal.substring(uriPrefix.length(), literal.length() - uriSuffix.length());
} else {
throw new EdmPrimitiveTypeException("The literal '" + literal + "' has illegal content.");
}
} }
@Override @Override
@ -117,26 +115,6 @@ public final class EdmNull implements EdmPrimitiveType {
return new FullQualifiedName(getNamespace(), getName()).getFullQualifiedNameAsString(); return new FullQualifiedName(getNamespace(), getName()).getFullQualifiedNameAsString();
} }
protected <T> T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength,
final Integer precision,
final Integer scale, final Boolean isUnicode, final 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());
}
}
protected <T> String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength,
final Integer precision,
final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException {
return "null";
}
@Override @Override
public boolean equals(final Object obj) { public boolean equals(final Object obj) {
return this == obj || obj != null && getClass() == obj.getClass(); return this == obj || obj != null && getClass() == obj.getClass();
@ -146,20 +124,4 @@ public final class EdmNull implements EdmPrimitiveType {
public int hashCode() { public int hashCode() {
return getClass().hashCode(); return getClass().hashCode();
} }
@Override
public String getNamespace() {
return EDM_NAMESPACE;
}
@Override
public String getName() {
return getClass().getSimpleName().substring(3);
}
@Override
public EdmTypeKind getKind() {
return EdmTypeKind.PRIMITIVE;
}
} }