[OLINGO-194] Using enum values as key or in search filters

This commit is contained in:
Francesco Chicchiriccò 2014-03-24 13:32:09 +01:00
parent 4a19c8dbc5
commit c1b8976e9b
14 changed files with 280 additions and 33 deletions

View File

@ -18,10 +18,32 @@
*/
package org.apache.olingo.client.api.uri.v4;
import java.util.Map;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.olingo.client.api.uri.CommonURIBuilder;
import org.apache.olingo.client.api.uri.QueryOption;
import org.apache.olingo.commons.api.edm.EdmEnumType;
public interface URIBuilder extends CommonURIBuilder<URIBuilder> {
/**
* Appends enum key segment to the URI.
*
* @param enumType enum type
* @param memberName enum member name
* @return current URIBuilder instance
*/
URIBuilder appendKeySegment(EdmEnumType enumType, String memberName);
/**
* Appends key segment to the URI, for multiple keys.
*
* @param enumValues enum segment values.
* @param segmentValues segment values.
* @return current URIBuilder instance
*/
URIBuilder appendKeySegment(Map<String, Pair<EdmEnumType, String>> enumValues, Map<String, Object> segmentValues);
/**
* Appends Singleton segment to the URI.
*

View File

@ -20,12 +20,19 @@ package org.apache.olingo.client.core.uri;
import org.apache.olingo.client.api.uri.FilterArg;
import org.apache.olingo.client.api.uri.CommonFilterArgFactory;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
/**
* OData filter arguments factory.
*/
public abstract class AbstractFilterArgFactory implements CommonFilterArgFactory {
private final ODataServiceVersion version;
public AbstractFilterArgFactory(final ODataServiceVersion version) {
this.version = version;
}
@Override
public FilterArg _null() {
return new FilterConst("null");
@ -38,7 +45,7 @@ public abstract class AbstractFilterArgFactory implements CommonFilterArgFactory
@Override
public FilterArg literal(final Object value) {
return new FilterLiteral(value);
return new FilterLiteral(version, value);
}
@Override

View File

@ -21,11 +21,18 @@ package org.apache.olingo.client.core.uri;
import org.apache.olingo.client.api.uri.FilterArg;
import org.apache.olingo.client.api.uri.CommonFilterFactory;
import org.apache.olingo.client.api.uri.URIFilter;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public abstract class AbstractFilterFactory implements CommonFilterFactory {
private static final long serialVersionUID = -6141317149802621836L;
protected final ODataServiceVersion version;
public AbstractFilterFactory(final ODataServiceVersion version) {
this.version = version;
}
@Override
public URIFilter match(final FilterArg arg) {
return new MatchFilter(arg);

View File

@ -30,6 +30,7 @@ import org.apache.olingo.client.api.uri.QueryOption;
import org.apache.olingo.client.api.uri.SegmentType;
import org.apache.olingo.client.api.uri.CommonURIBuilder;
import org.apache.olingo.client.api.uri.URIFilter;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -63,6 +64,8 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
}
private final ODataServiceVersion version;
protected final List<Segment> segments = new ArrayList<Segment>();
/**
@ -76,7 +79,8 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
* @param serviceRoot absolute URL (schema, host and port included) representing the location of the root of the data
* service.
*/
protected AbstractURIBuilder(final String serviceRoot) {
protected AbstractURIBuilder(final ODataServiceVersion version, final String serviceRoot) {
this.version = version;
segments.add(new Segment(SegmentType.SERVICEROOT, serviceRoot));
}
@ -101,7 +105,7 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
@Override
public UB appendKeySegment(final Object val) {
final String segValue = URIUtils.escape(val);
final String segValue = URIUtils.escape(version, val);
segments.add(new Segment(SegmentType.KEY, "(" + segValue + ")"));
return getThis();
@ -116,7 +120,7 @@ public abstract class AbstractURIBuilder<UB extends CommonURIBuilder<?>> impleme
} else {
final StringBuilder keyBuilder = new StringBuilder().append('(');
for (Map.Entry<String, Object> entry : segmentValues.entrySet()) {
keyBuilder.append(entry.getKey()).append('=').append(URIUtils.escape(entry.getValue()));
keyBuilder.append(entry.getKey()).append('=').append(URIUtils.escape(version, entry.getValue()));
keyBuilder.append(',');
}
keyBuilder.deleteCharAt(keyBuilder.length() - 1).append(')');

View File

@ -19,22 +19,26 @@
package org.apache.olingo.client.core.uri;
import org.apache.olingo.client.api.uri.FilterArg;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
/**
* Filter value literals; obtain instances via <tt>FilterArgFactory</tt>.
*
* @see FilterArgFactory
* @see org.apache.olingo.client.api.uri.v3.FilterArgFactory
*/
public class FilterLiteral implements FilterArg {
private final ODataServiceVersion version;
private final Object value;
FilterLiteral(final Object value) {
FilterLiteral(final ODataServiceVersion version, final Object value) {
this.version = version;
this.value = value;
}
@Override
public String build() {
return URIUtils.escape(value);
return URIUtils.escape(version, value);
}
}

View File

@ -21,6 +21,7 @@ package org.apache.olingo.client.core.uri;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URLEncoder;
@ -30,18 +31,26 @@ import java.util.UUID;
import javax.xml.datatype.Duration;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.entity.InputStreamEntity;
import org.apache.olingo.client.api.CommonODataClient;
import org.apache.olingo.commons.api.Constants;
import org.apache.olingo.commons.api.edm.EdmEntityContainer;
import org.apache.olingo.commons.api.edm.EdmFunctionImport;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDate;
import org.apache.olingo.commons.core.edm.primitivetype.EdmDateTime;
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.EdmInt64;
import org.apache.olingo.commons.core.edm.primitivetype.EdmSingle;
import org.apache.olingo.commons.core.edm.primitivetype.EdmTime;
import org.apache.olingo.commons.core.edm.primitivetype.EdmTimeOfDay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -141,41 +150,186 @@ public final class URIUtils {
return result.toString();
}
private static String prefix(final ODataServiceVersion version, final EdmPrimitiveTypeKind typeKind) {
String result = StringUtils.EMPTY;
if (version == ODataServiceVersion.V30) {
switch (typeKind) {
case Guid:
result = "guid'";
break;
case DateTime:
result = "datetime'";
break;
case DateTimeOffset:
result = "datetimeoffset'";
break;
case Binary:
result = "X'";
break;
default:
}
} else {
switch (typeKind) {
case Binary:
result = "binary'";
break;
default:
}
}
return result;
}
private static String suffix(final ODataServiceVersion version, final EdmPrimitiveTypeKind typeKind) {
String result = StringUtils.EMPTY;
if (version == ODataServiceVersion.V30) {
switch (typeKind) {
case Guid:
case DateTime:
case DateTimeOffset:
case Binary:
result = "'";
break;
case Decimal:
result = "M";
break;
case Double:
result = "D";
break;
case Single:
result = "f";
break;
case Int64:
result = "L";
break;
default:
}
} else {
switch (typeKind) {
case Binary:
result = "'";
break;
default:
}
}
return result;
}
private static String timestamp(final ODataServiceVersion version, final Timestamp timestamp)
throws UnsupportedEncodingException, EdmPrimitiveTypeException {
return version == ODataServiceVersion.V30
? prefix(version, EdmPrimitiveTypeKind.DateTime)
+ URLEncoder.encode(EdmDateTime.getInstance().
valueToString(timestamp, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8)
+ suffix(version, EdmPrimitiveTypeKind.DateTime)
: URLEncoder.encode(EdmDateTimeOffset.getInstance().
valueToString(timestamp, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8);
}
private static String calendar(final ODataServiceVersion version, final Calendar calendar)
throws UnsupportedEncodingException, EdmPrimitiveTypeException {
String result;
if (calendar.get(Calendar.ZONE_OFFSET) == 0) {
if (version == ODataServiceVersion.V30) {
result = prefix(version, EdmPrimitiveTypeKind.DateTime)
+ URLEncoder.encode(EdmDateTime.getInstance().
valueToString(calendar, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8)
+ suffix(version, EdmPrimitiveTypeKind.DateTime);
} else {
if (calendar.get(Calendar.YEAR) == 0 && calendar.get(Calendar.MONTH) == 0
&& calendar.get(Calendar.DAY_OF_MONTH) == 0) {
result = URLEncoder.encode(EdmTimeOfDay.getInstance().
valueToString(calendar, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8);
} else {
result = URLEncoder.encode(EdmDate.getInstance().
valueToString(calendar, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8);
}
}
} else {
result = prefix(version, EdmPrimitiveTypeKind.DateTimeOffset)
+ URLEncoder.encode(EdmDateTimeOffset.getInstance().
valueToString(calendar, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8)
+ suffix(version, EdmPrimitiveTypeKind.DateTimeOffset);
}
return result;
}
private static String duration(final ODataServiceVersion version, final Duration duration)
throws UnsupportedEncodingException, EdmPrimitiveTypeException {
return version == ODataServiceVersion.V30
? "time'" + URLEncoder.encode(EdmTime.getInstance().
valueToString(duration, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8) + "'"
: "duration'" + URLEncoder.encode(EdmDuration.getInstance().
valueToString(duration, null, null, Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null),
Constants.UTF8) + "'";
}
/**
* Turns primitive values into their respective URI representation.
*
* @param obj primitive value
* @return URI representation
*/
public static String escape(final Object obj) {
public static String escape(final ODataServiceVersion version, final Object obj) {
String value;
try {
value = (obj instanceof UUID)
? "guid'" + obj.toString() + "'"
value = (obj instanceof Boolean)
? BooleanUtils.toStringTrueFalse((Boolean) obj)
: (obj instanceof UUID)
? prefix(version, EdmPrimitiveTypeKind.Guid)
+ obj.toString()
+ suffix(version, EdmPrimitiveTypeKind.Guid)
: (obj instanceof byte[])
? "X'" + Hex.encodeHexString((byte[]) obj) + "'"
? prefix(version, EdmPrimitiveTypeKind.Binary)
+ Hex.encodeHexString((byte[]) obj)
+ suffix(version, EdmPrimitiveTypeKind.Binary)
: (obj instanceof Timestamp)
? "datetime'" + URLEncoder.encode(EdmDateTime.getInstance().
valueToString(obj, null, null, null, null, null), Constants.UTF8) + "'"
? timestamp(version, (Timestamp) obj)
: (obj instanceof Calendar)
? "datetimeoffset'" + URLEncoder.encode(EdmDateTimeOffset.getInstance().
valueToString(obj, null, null, null, null, null), Constants.UTF8) + "'"
? calendar(version, (Calendar) obj)
: (obj instanceof Duration)
? "time'" + URLEncoder.encode(EdmTime.getInstance().
valueToString(obj, null, null, null, null, null), Constants.UTF8) + "'"
? duration(version, (Duration) obj)
: (obj instanceof BigDecimal)
? EdmDecimal.getInstance().valueToString(obj, null, null,
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null) + "M"
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
+ suffix(version, EdmPrimitiveTypeKind.Decimal)
: (obj instanceof Double)
? EdmDouble.getInstance().valueToString(obj, null, null,
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null) + "D"
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
+ suffix(version, EdmPrimitiveTypeKind.Double)
: (obj instanceof Float)
? EdmSingle.getInstance().valueToString(obj, null, null,
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null) + "f"
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
+ suffix(version, EdmPrimitiveTypeKind.Single)
: (obj instanceof Long)
? EdmInt64.getInstance().valueToString(obj, null, null,
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null) + "L"
Constants.DEFAULT_PRECISION, Constants.DEFAULT_SCALE, null)
+ suffix(version, EdmPrimitiveTypeKind.Int64)
: (obj instanceof String)
? "'" + URLEncoder.encode((String) obj, Constants.UTF8) + "'"
: obj.toString();
@ -186,7 +340,7 @@ public final class URIUtils {
return value;
}
public static InputStreamEntity buildInputStreamEntity(final CommonODataClient client, final InputStream input) {
InputStreamEntity entity;
if (client.getConfiguration().isUseChuncked()) {

View File

@ -22,9 +22,14 @@ import org.apache.olingo.client.api.uri.FilterArg;
import org.apache.olingo.client.api.uri.v3.FilterArgFactory;
import org.apache.olingo.client.core.uri.AbstractFilterArgFactory;
import org.apache.olingo.client.core.uri.FilterFunction;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class FilterArgFactoryImpl extends AbstractFilterArgFactory implements FilterArgFactory {
public FilterArgFactoryImpl(final ODataServiceVersion version) {
super(version);
}
@Override
public FilterArg substringof(final FilterArg first, final FilterArg second) {
return new FilterFunction("substringof", first, second);

View File

@ -21,14 +21,19 @@ package org.apache.olingo.client.core.uri.v3;
import org.apache.olingo.client.api.uri.v3.FilterArgFactory;
import org.apache.olingo.client.api.uri.v3.FilterFactory;
import org.apache.olingo.client.core.uri.AbstractFilterFactory;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class FilterFactoryImpl extends AbstractFilterFactory implements FilterFactory {
private static final long serialVersionUID = 1092594961118334631L;
public FilterFactoryImpl(final ODataServiceVersion version) {
super(version);
}
@Override
public FilterArgFactory getArgFactory() {
return new FilterArgFactoryImpl();
return new FilterArgFactoryImpl(version);
}
}

View File

@ -27,15 +27,21 @@ import org.apache.olingo.client.api.uri.QueryOption;
import org.apache.olingo.client.api.uri.SegmentType;
import org.apache.olingo.client.api.uri.v3.URIBuilder;
import org.apache.olingo.client.core.uri.AbstractURIBuilder;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class URIBuilderImpl extends AbstractURIBuilder<URIBuilder> implements URIBuilder {
private static final long serialVersionUID = -3506851722447870532L;
private final ODataServiceVersion version;
private final Configuration configuration;
public URIBuilderImpl(final Configuration configuration, final String serviceRoot) {
super(serviceRoot);
public URIBuilderImpl(final ODataServiceVersion version, final Configuration configuration,
final String serviceRoot) {
super(version, serviceRoot);
this.version = version;
this.configuration = configuration;
}
@ -70,7 +76,7 @@ public class URIBuilderImpl extends AbstractURIBuilder<URIBuilder> implements UR
@Override
public URIBuilder appendKeySegment(final Object val) {
if (configuration.isKeyAsSegment()) {
final String segValue = URIUtils.escape(val);
final String segValue = URIUtils.escape(version, val);
segments.add(new Segment(SegmentType.KEY_AS_SEGMENT, segValue));
} else {
super.appendKeySegment(val);

View File

@ -24,9 +24,14 @@ import org.apache.olingo.client.api.uri.v4.FilterArgFactory;
import org.apache.olingo.client.core.uri.AbstractFilterArgFactory;
import org.apache.olingo.client.core.uri.FilterFunction;
import org.apache.olingo.client.core.uri.FilterLambda;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class FilterArgFactoryImpl extends AbstractFilterArgFactory implements FilterArgFactory {
public FilterArgFactoryImpl(final ODataServiceVersion version) {
super(version);
}
@Override
public FilterArg contains(final FilterArg first, final FilterArg second) {
return new FilterFunction("contains", first, second);

View File

@ -26,14 +26,19 @@ import org.apache.olingo.client.core.uri.AbstractFilterFactory;
import org.apache.olingo.client.core.uri.FilterProperty;
import org.apache.olingo.client.core.uri.HasFilter;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class FilterFactoryImpl extends AbstractFilterFactory implements FilterFactory {
private static final long serialVersionUID = -5358934829490623191L;
public FilterFactoryImpl(ODataServiceVersion version) {
super(version);
}
@Override
public FilterArgFactory getArgFactory() {
return new FilterArgFactoryImpl();
return new FilterArgFactoryImpl(version);
}
@Override

View File

@ -18,18 +18,41 @@
*/
package org.apache.olingo.client.core.uri.v4;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.olingo.client.api.uri.QueryOption;
import org.apache.olingo.client.api.uri.SegmentType;
import org.apache.olingo.client.api.uri.v4.URIBuilder;
import org.apache.olingo.client.core.uri.AbstractURIBuilder;
import org.apache.olingo.commons.api.edm.EdmEnumType;
import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
public class URIBuilderImpl extends AbstractURIBuilder<URIBuilder> implements URIBuilder {
private static final long serialVersionUID = -3506851722447870532L;
public URIBuilderImpl(final String serviceRoot) {
super(serviceRoot);
public URIBuilderImpl(final ODataServiceVersion version, final String serviceRoot) {
super(version, serviceRoot);
}
@Override
public URIBuilder appendKeySegment(final EdmEnumType enumType, final String memberName) {
return appendKeySegment(enumType.toUriLiteral(memberName));
}
@Override
public URIBuilder appendKeySegment(final Map<String, Pair<EdmEnumType, String>> enumValues,
final Map<String, Object> segmentValues) {
final Map<String, Object> values = new LinkedHashMap<String, Object>();
for (Map.Entry<String, Pair<EdmEnumType, String>> entry : enumValues.entrySet()) {
values.put(entry.getKey(), entry.getValue().getKey().toUriLiteral(entry.getValue().getValue()));
}
values.putAll(segmentValues);
return appendKeySegment(values);
}
@Override

View File

@ -54,7 +54,7 @@ public class ODataClientImpl extends AbstractODataClient implements ODataClient
private final Configuration configuration = new ConfigurationImpl();
private final FilterFactory filterFactory = new FilterFactoryImpl();
private final FilterFactory filterFactory = new FilterFactoryImpl(getServiceVersion());
private final ODataDeserializer deserializer = new ODataDeserializerImpl(getServiceVersion());
@ -95,7 +95,7 @@ public class ODataClientImpl extends AbstractODataClient implements ODataClient
@Override
public URIBuilder getURIBuilder(final String serviceRoot) {
return new URIBuilderImpl(configuration, serviceRoot);
return new URIBuilderImpl(getServiceVersion(), configuration, serviceRoot);
}
@Override

View File

@ -54,7 +54,7 @@ public class ODataClientImpl extends AbstractODataClient implements ODataClient
private final Configuration configuration = new ConfigurationImpl();
private final FilterFactory filterFactory = new FilterFactoryImpl();
private final FilterFactory filterFactory = new FilterFactoryImpl(getServiceVersion());
private final ODataDeserializer deserializer = new ODataDeserializerImpl(getServiceVersion());
@ -94,7 +94,7 @@ public class ODataClientImpl extends AbstractODataClient implements ODataClient
@Override
public URIBuilder getURIBuilder(final String serviceRoot) {
return new URIBuilderImpl(serviceRoot);
return new URIBuilderImpl(getServiceVersion(), serviceRoot);
}
@Override