From 67922d810631590c2d6faa5a47b4ee3715caccdf Mon Sep 17 00:00:00 2001 From: thboileau Date: Sat, 23 Jul 2016 18:15:31 +0200 Subject: [PATCH 1/2] Ensured all calls to the service are properly configured. --- .../src/org/restlet/ext/odata/Generator.java | 18 ++++- .../src/org/restlet/ext/odata/Service.java | 77 +++++++++---------- 2 files changed, 54 insertions(+), 41 deletions(-) diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java index d4e78cf36a..a0fe1ed571 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java @@ -31,6 +31,7 @@ import java.util.HashMap; import java.util.Map; +import org.restlet.data.ChallengeResponse; import org.restlet.data.CharacterSet; import org.restlet.data.MediaType; import org.restlet.data.Reference; @@ -61,8 +62,7 @@ public class Generator { * Takes two (or three) parameters:
*
    *
  1. The URI of the OData service
  2. - *
  3. The output directory (optional, used the current directory by - * default)
  4. + *
  5. The output directory (optional, used the current directory by default)
  6. *
  7. The name of the generated service class name (optional)
  8. *
* @@ -164,6 +164,9 @@ public static void main(String[] args) { /** The name of the service class (in case there is only one in the schema). */ private String serviceClassName; + /** The credentials used to request the OData service. */ + private ChallengeResponse serviceCredentials; + /** The URI of the target data service. */ private Reference serviceRef; @@ -231,6 +234,7 @@ public Generator(String serviceUri, String serviceClassName) { */ public void generate(File outputDir) throws Exception { Service service = new Service(serviceRef); + service.setCredentials(serviceCredentials); Metadata metadata = (Metadata) service.getMetadata(); if (metadata == null) { throw new Exception("Can't get the metadata for this service: " @@ -363,4 +367,14 @@ public void generate(File outputDir) throws Exception { public void generate(String outputDir) throws Exception { generate(new File(outputDir)); } + + /** + * Set the credentials used to request the OData service. + * + * @param serviceCredentials + * The credentials. + */ + public void setServiceCredentials(ChallengeResponse serviceCredentials) { + this.serviceCredentials = serviceCredentials; + } } diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java index 504f5972de..15cca0c1db 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java @@ -112,6 +112,8 @@ public class Service { /** The credentials used to authenticate requests. */ private ChallengeResponse credentials; + private boolean hasServiceUriBeenChecked; + /** The latest request sent to the service. */ private Request latestRequest; @@ -146,36 +148,7 @@ public class Service { * The reference to the WCF service. */ public Service(Reference serviceRef) { - try { - // Test the given service URI which may be actually redirected. - ClientResource cr = new ClientResource(serviceRef); - if (cr.getNext() == null) { - // The context does not provide a client connector. - // Let instantiate our own. - Protocol rProtocol = cr.getProtocol(); - Reference rReference = cr.getReference(); - Protocol protocol = (rProtocol != null) ? rProtocol - : (rReference != null) ? rReference.getSchemeProtocol() - : null; - - if (protocol != null) { - this.clientConnector = new Client(protocol); - // Set the next handler for reuse - cr.setNext(this.clientConnector); - } - } - - cr.setFollowingRedirects(false); - cr.get(); - - if (cr.getStatus().isRedirection()) { - this.serviceRef = cr.getLocationRef(); - } else { - this.serviceRef = cr.getReference(); - } - } catch (Throwable e) { - this.serviceRef = serviceRef; - } + this.serviceRef = serviceRef; } /** @@ -253,6 +226,35 @@ public void addLink(Object source, String sourceProperty, Object target) } } + private void checkServiceReference(Reference serviceRef) { + try { + // Test the given service URI which may be actually redirected. + ClientResource cr = createResource(serviceRef); + if (cr.getNext() == null) { + // The context does not provide a client connector. + // Let instantiate our own. + Protocol rProtocol = cr.getProtocol(); + Reference rReference = cr.getReference(); + Protocol protocol = (rProtocol != null) ? rProtocol + : (rReference != null) ? rReference.getSchemeProtocol() + : null; + + if (protocol != null) { + this.clientConnector = new Client(protocol); + // Set the next handler for reuse + cr.setNext(this.clientConnector); + } + } + + cr.setFollowingRedirects(true); + cr.get(); + this.serviceRef = cr.getResponse().getRequest().getResourceRef(); + } catch (Throwable e) { + this.serviceRef = serviceRef; + } + hasServiceUriBeenChecked = true; + } + /** * Creates a query to a specific entity hosted by this service. * @@ -288,7 +290,7 @@ public ClientResource createResource(Reference reference) { resource.setChallengeResponse(getCredentials()); if (getClientVersion() != null || getMaxClientVersion() != null) { - Series
headers = new Series
(Header.class); + Series
headers = resource.getRequest().getHeaders(); if (getClientVersion() != null) { headers.add("DataServiceVersion", getClientVersion()); @@ -297,8 +299,6 @@ public ClientResource createResource(Reference reference) { if (getMaxClientVersion() != null) { headers.add("MaxDataServiceVersion", getMaxClientVersion()); } - - resource.setAttribute(HeaderConstants.ATTRIBUTE_HEADERS, headers); } return resource; @@ -533,6 +533,9 @@ public String getServerVersion() { * @return The reference to the WCF service. */ public Reference getServiceRef() { + if (!hasServiceUriBeenChecked) { + checkServiceReference(serviceRef); + } return serviceRef; } @@ -816,9 +819,7 @@ public Reference getValueRef(Object entity) { * @return The representation returned by the invocation of the service. * @throws ResourceException * Thrown when the service call is not successfull. - * @see Service - * Operations + * @see Service Operations */ public Representation invokeComplex(String service, Series parameters) throws ResourceException { @@ -879,9 +880,7 @@ public Representation invokeComplex(String service, * Thrown when the service call is not successfull. * @throws Exception * Thrown when the value cannot be parsed. - * @see Service - * Operations + * @see Service Operations */ public String invokeSimple(String service, Series parameters) throws ResourceException, Exception { From b8234b1116a170f86855ba1b24edbb9eb90ba47a Mon Sep 17 00:00:00 2001 From: thboileau Date: Sat, 30 Jul 2016 17:13:45 +0200 Subject: [PATCH 2/2] Allows users of OData extension to handle specific data types. --- .../org/restlet/ext/odata/EdmConverter.java | 287 ++++++++++++++++++ .../src/org/restlet/ext/odata/Generator.java | 22 +- .../restlet/ext/odata/JavaTypeHandler.java | 93 ++++++ .../src/org/restlet/ext/odata/Service.java | 23 +- .../ext/odata/internal/edm/Metadata.java | 13 +- .../ext/odata/internal/edm/TypeUtils.java | 282 +++-------------- .../odata/internal/reflect/ReflectUtils.java | 11 +- .../restlet/engine/util/CollectionsUtils.java | 46 +++ 8 files changed, 500 insertions(+), 277 deletions(-) create mode 100644 modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java create mode 100644 modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java create mode 100644 modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java new file mode 100644 index 0000000000..7d880655d9 --- /dev/null +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/EdmConverter.java @@ -0,0 +1,287 @@ +package org.restlet.ext.odata; + +import static org.restlet.ext.odata.internal.edm.TypeUtils.dateTimeFormats; +import static org.restlet.ext.odata.internal.edm.TypeUtils.decimalFormat; +import static org.restlet.ext.odata.internal.edm.TypeUtils.doubleFormat; +import static org.restlet.ext.odata.internal.edm.TypeUtils.singleFormat; +import static org.restlet.ext.odata.internal.edm.TypeUtils.timeFormat; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmBinary; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmBoolean; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmByte; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmDateTime; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmDecimal; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmDouble; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmInt16; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmInt32; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmInt64; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmSingle; +import static org.restlet.ext.odata.internal.edm.TypeUtils.toEdmTime; + +import java.util.Date; + +import org.restlet.Context; +import org.restlet.engine.util.Base64; +import org.restlet.engine.util.DateUtils; +import org.restlet.ext.odata.internal.edm.Type; + +/** + * Util class used to convert values to and from Edm types.
+ * Can be overriden to extends basic behaviour. + */ +public class EdmConverter { + + /** + * Converts the String representation of the target WCF type to its + * corresponding value. + * + * @param value + * The value to convert. + * @param adoNetType + * The target WCF type. + * @return The converted value. + */ + public Object fromEdm(String value, String adoNetType) { + if (value == null) { + return null; + } + + Object result = null; + try { + if (adoNetType.endsWith("Binary")) { + result = Base64.decode(value); + } else if (adoNetType.endsWith("Boolean")) { + result = Boolean.valueOf(value); + } else if (adoNetType.endsWith("DateTime")) { + result = DateUtils.parse(value, dateTimeFormats); + } else if (adoNetType.endsWith("DateTimeOffset")) { + result = DateUtils.parse(value, dateTimeFormats); + } else if (adoNetType.endsWith("Time")) { + result = timeFormat.parseObject(value); + } else if (adoNetType.endsWith("Decimal")) { + result = decimalFormat.parseObject(value); + } else if (adoNetType.endsWith("Single")) { + result = singleFormat.parseObject(value); + } else if (adoNetType.endsWith("Double")) { + result = doubleFormat.parseObject(value); + } else if (adoNetType.endsWith("Guid")) { + result = value; + } else if (adoNetType.endsWith("Int16")) { + result = Short.valueOf(value); + } else if (adoNetType.endsWith("Int32")) { + result = Integer.valueOf(value); + } else if (adoNetType.endsWith("Int64")) { + result = Long.valueOf(value); + } else if (adoNetType.endsWith("Byte")) { + result = Byte.valueOf(value); + } else if (adoNetType.endsWith("String")) { + result = value; + } + } catch (Exception e) { + Context.getCurrentLogger().warning( + "Cannot convert " + value + " from this EDM type " + + adoNetType); + } + + return result; + } + + /** + * Returns the literal form of the given value. + * + * @param value + * The value to convert. + * @param adoNetType + * The type of the value. + * @return The literal form of the given value. + * @see Abstract Type + * System + */ + public String getLiteralForm(String value, String adoNetType) { + if (value == null) { + return null; + } + + String result = null; + try { + if (adoNetType.endsWith("Binary")) { + result = "'" + value + "'"; + } else if (adoNetType.endsWith("DateTime")) { + result = "datetime'" + value + "'"; + } else if (adoNetType.endsWith("DateTimeOffset")) { + result = "datetimeoffset'" + value + "'"; + } else if (adoNetType.endsWith("Time")) { + result = "time'" + value + "'"; + } else if (adoNetType.endsWith("Guid")) { + result = "guid'" + value + "'"; + } else if (adoNetType.endsWith("String")) { + result = "'" + value + "'"; + } + } catch (Exception e) { + Context.getCurrentLogger().warning( + "Cannot convert " + value + " from this EDM type " + + adoNetType); + } + + return result; + } + + /** + * Converts a value to the String representation of the target WCF type. + * + * @param value + * The value to convert. + * @param type + * The target WCF type. + * @return The converted value. + */ + public String toEdm(Object value, Type type) { + String adoNetType = type.getName(); + if (value == null || adoNetType == null) { + return null; + } + + String result = null; + if (adoNetType.endsWith("Binary")) { + if ((byte[].class).isAssignableFrom(value.getClass())) { + result = toEdmBinary((byte[]) value); + } + } else if (adoNetType.endsWith("Boolean")) { + if ((Boolean.class).isAssignableFrom(value.getClass())) { + result = toEdmBoolean((Boolean) value); + } + } else if (adoNetType.endsWith("DateTime")) { + if ((Date.class).isAssignableFrom(value.getClass())) { + result = toEdmDateTime((Date) value); + } + } else if (adoNetType.endsWith("DateTimeOffset")) { + if ((Date.class).isAssignableFrom(value.getClass())) { + result = toEdmDateTime((Date) value); + } + } else if (adoNetType.endsWith("Time")) { + if ((Long.class).isAssignableFrom(value.getClass())) { + result = toEdmTime((Long) value); + } + } else if (adoNetType.endsWith("Decimal")) { + if ((Double.class).isAssignableFrom(value.getClass())) { + result = toEdmDecimal((Double) value); + } + } else if (adoNetType.endsWith("Single")) { + if ((Float.class).isAssignableFrom(value.getClass())) { + result = toEdmSingle((Float) value); + } else if ((Double.class).isAssignableFrom(value.getClass())) { + result = toEdmSingle((Double) value); + } + } else if (adoNetType.endsWith("Double")) { + if ((Double.class).isAssignableFrom(value.getClass())) { + result = toEdmDouble((Double) value); + } + } else if (adoNetType.endsWith("Guid")) { + result = value.toString(); + } else if (adoNetType.endsWith("Int16")) { + if ((Short.class).isAssignableFrom(value.getClass())) { + result = toEdmInt16((Short) value); + } + } else if (adoNetType.endsWith("Int32")) { + if ((Integer.class).isAssignableFrom(value.getClass())) { + result = toEdmInt32((Integer) value); + } + } else if (adoNetType.endsWith("Int64")) { + if ((Long.class).isAssignableFrom(value.getClass())) { + result = toEdmInt64((Long) value); + } + } else if (adoNetType.endsWith("Byte")) { + if ((Byte.class).isAssignableFrom(value.getClass())) { + result = toEdmByte((Byte) value); + } + } else if (adoNetType.endsWith("String")) { + result = value.toString(); + } + + if (result == null) { + result = value.toString(); + } + + return result; + } + + /** + * Converts a value to the String representation of the target WCF type when + * used a key in the URIs. + * + * @param value + * The value to convert. + * @param type + * The target WCF type. + * @return The converted value. + */ + public String toEdmKey(Object value, Type type) { + String adoNetType = type.getName(); + if (value == null || adoNetType == null) { + return null; + } + + String result = null; + if (adoNetType.endsWith("Binary")) { + if ((byte[].class).isAssignableFrom(value.getClass())) { + result = toEdmBinary((byte[]) value); + } + } else if (adoNetType.endsWith("Boolean")) { + if ((Boolean.class).isAssignableFrom(value.getClass())) { + result = toEdmBoolean((Boolean) value); + } + } else if (adoNetType.endsWith("DateTime")) { + if ((Date.class).isAssignableFrom(value.getClass())) { + result = toEdmDateTime((Date) value); + } + } else if (adoNetType.endsWith("DateTimeOffset")) { + if ((Date.class).isAssignableFrom(value.getClass())) { + result = toEdmDateTime((Date) value); + } + } else if (adoNetType.endsWith("Time")) { + if ((Long.class).isAssignableFrom(value.getClass())) { + result = toEdmTime((Long) value); + } + } else if (adoNetType.endsWith("Decimal")) { + if ((Double.class).isAssignableFrom(value.getClass())) { + result = toEdmDecimal((Double) value); + } + } else if (adoNetType.endsWith("Single")) { + if ((Float.class).isAssignableFrom(value.getClass())) { + result = toEdmSingle((Float) value); + } else if ((Double.class).isAssignableFrom(value.getClass())) { + result = toEdmSingle((Double) value); + } + } else if (adoNetType.endsWith("Double")) { + if ((Double.class).isAssignableFrom(value.getClass())) { + result = toEdmDouble((Double) value); + } + } else if (adoNetType.endsWith("Guid")) { + result = value.toString(); + } else if (adoNetType.endsWith("Int16")) { + if ((Short.class).isAssignableFrom(value.getClass())) { + result = toEdmInt16((Short) value); + } + } else if (adoNetType.endsWith("Int32")) { + if ((Integer.class).isAssignableFrom(value.getClass())) { + result = toEdmInt32((Integer) value); + } + } else if (adoNetType.endsWith("Int64")) { + if ((Long.class).isAssignableFrom(value.getClass())) { + result = toEdmInt64((Long) value); + } + } else if (adoNetType.endsWith("Byte")) { + if ((Byte.class).isAssignableFrom(value.getClass())) { + result = toEdmByte((Byte) value); + } + } else if (adoNetType.endsWith("String")) { + result = "'" + value.toString() + "'"; + } + + if (result == null) { + result = value.toString(); + } + + return result; + } + +} diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java index a0fe1ed571..b31a4b9b74 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Generator.java @@ -49,6 +49,8 @@ import freemarker.template.Configuration; +import static org.restlet.engine.util.CollectionsUtils.isNullOrEmpty; + /** * Code generator for accessing OData services. The generator use metadata * exposed by an online service to generate client-side artifacts facilitating @@ -257,13 +259,9 @@ public void generate(File outputDir) throws Exception { .getText()); for (Schema schema : metadata.getSchemas()) { - if ((schema.getEntityTypes() != null && !schema.getEntityTypes() - .isEmpty()) - || (schema.getComplexTypes() != null && !schema - .getComplexTypes().isEmpty())) { + if (!isNullOrEmpty(schema.getEntityTypes()) || !isNullOrEmpty(schema.getComplexTypes())) { String packageName = TypeUtils.getPackageName(schema); - File packageDir = new File(outputDir, packageName.replace(".", - System.getProperty("file.separator"))); + File packageDir = new File(outputDir, packageName.replace(".", System.getProperty("file.separator"))); packageDir.mkdirs(); // For each entity type @@ -276,13 +274,11 @@ public void generate(File outputDir) throws Exception { dataModel.put("className", className); dataModel.put("packageName", packageName); - TemplateRepresentation templateRepresentation = new TemplateRepresentation( - entityTmpl, fmc, dataModel, MediaType.TEXT_PLAIN); + TemplateRepresentation templateRepresentation = new TemplateRepresentation(entityTmpl, fmc, dataModel, MediaType.TEXT_PLAIN); templateRepresentation.setCharacterSet(CharacterSet.UTF_8); // Write the template representation as a Java class - OutputStream fos = new FileOutputStream(new File( - packageDir, type.getClassName() + ".java")); + OutputStream fos = new FileOutputStream(new File(packageDir, type.getClassName() + ".java")); templateRepresentation.write(fos); fos.flush(); } @@ -308,8 +304,7 @@ public void generate(File outputDir) throws Exception { } } } - if (metadata.getContainers() != null - && !metadata.getContainers().isEmpty()) { + if (!isNullOrEmpty(metadata.getContainers())) { for (EntityContainer entityContainer : metadata.getContainers()) { Schema schema = entityContainer.getSchema(); // Generate Service subclass @@ -349,8 +344,7 @@ public void generate(File outputDir) throws Exception { templateRepresentation.setCharacterSet(CharacterSet.UTF_8); // Write the template representation as a Java class - OutputStream fos = new FileOutputStream(new File(outputDir, - className + ".java")); + OutputStream fos = new FileOutputStream(new File(outputDir, className + ".java")); templateRepresentation.write(fos); fos.flush(); } diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java new file mode 100644 index 0000000000..1f86de8d2b --- /dev/null +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/JavaTypeHandler.java @@ -0,0 +1,93 @@ +package org.restlet.ext.odata; + +import java.util.Date; + +/** + * Handles the conversion from Edm type to Java class. + */ +public class JavaTypeHandler { + + /** + * Returns the corresponding Java class or scalar type. + * + * @param edmTypeName + * The type name. + * @return The corresponding Java class or scalar type. + */ + public Class toJavaClass(String edmTypeName) { + Class result = Object.class; + if (edmTypeName.endsWith("Binary")) { + result = byte[].class; + } else if (edmTypeName.endsWith("Boolean")) { + result = Boolean.class; + } else if (edmTypeName.endsWith("DateTime")) { + result = Date.class; + } else if (edmTypeName.endsWith("DateTimeOffset")) { + result = Date.class; + } else if (edmTypeName.endsWith("Time")) { + result = Long.class; + } else if (edmTypeName.endsWith("Decimal")) { + result = Double.class; + } else if (edmTypeName.endsWith("Single")) { + result = Double.class; + } else if (edmTypeName.endsWith("Double")) { + result = Double.class; + } else if (edmTypeName.endsWith("Guid")) { + result = String.class; + } else if (edmTypeName.endsWith("Int16")) { + result = Short.class; + } else if (edmTypeName.endsWith("Int32")) { + result = Integer.class; + } else if (edmTypeName.endsWith("Int64")) { + result = Long.class; + } else if (edmTypeName.endsWith("Byte")) { + result = Byte.class; + } else if (edmTypeName.endsWith("String")) { + result = String.class; + } + + return result; + } + /** + * Returns the name of the corresponding Java class or scalar type. + * + * @param edmTypeName + * The type name. + * @return The name of the corresponding Java class or scalar type. + */ + public String toJavaTypeName(String edmTypeName) { + String result = "Object"; + if (edmTypeName.endsWith("Binary")) { + result = "byte[]"; + } else if (edmTypeName.endsWith("Boolean")) { + result = "boolean"; + } else if (edmTypeName.endsWith("DateTime")) { + result = "Date"; + } else if (edmTypeName.endsWith("DateTimeOffset")) { + result = "Date"; + } else if (edmTypeName.endsWith("Time")) { + result = "long"; + } else if (edmTypeName.endsWith("Decimal")) { + result = "double"; + } else if (edmTypeName.endsWith("Single")) { + result = "double"; + } else if (edmTypeName.endsWith("Double")) { + result = "double"; + } else if (edmTypeName.endsWith("Guid")) { + result = "String"; + } else if (edmTypeName.endsWith("Int16")) { + result = "short"; + } else if (edmTypeName.endsWith("Int32")) { + result = "int"; + } else if (edmTypeName.endsWith("Int64")) { + result = "long"; + } else if (edmTypeName.endsWith("Byte")) { + result = "byte"; + } else if (edmTypeName.endsWith("String")) { + result = "String"; + } + + return result; + } + +} diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java index 15cca0c1db..9c20762a9c 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/Service.java @@ -848,8 +848,7 @@ public Representation invokeComplex(String service, .getParameters()) { resource.getReference().addQueryParameter( parameter.getName(), - TypeUtils.getLiteralForm(parameters - .getFirstValue(parameter.getName()), + TypeUtils.getLiteralForm(parameters.getFirstValue(parameter.getName()), parameter.getType())); } } @@ -955,6 +954,26 @@ public void loadProperty(Object entity, String propertyName) { } } + /** + * Allows to specify a new Edm type converter. + * + * @param edmConverter + * The new EdmType converter. + */ + public void registerEdmConverter(EdmConverter edmConverter) { + TypeUtils.registerEdmConverter(edmConverter); + } + + /** + * Allows to specify a new Java type handler. + * + * @param javaTypeHandler + * The new Java type handler. + */ + public static void registerJavaTypeHandler(JavaTypeHandler javaTypeHandler) { + TypeUtils.registerJavaTypeHandler(javaTypeHandler); + } + /** * Sets the version of the OData protocol extensions defined in every * request issued by this service. diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java index 0dcd0816ee..84e9086156 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/Metadata.java @@ -34,6 +34,8 @@ import org.restlet.ext.xml.SaxRepresentation; import org.restlet.representation.Representation; +import static org.restlet.engine.util.CollectionsUtils.isNullOrEmpty; + /** * Represents the metadata of an OData service. * @@ -212,7 +214,7 @@ public EntityType getEntityType(Class entityClass) { public String getKeyValue(EntityType type, Object entity) { StringBuffer result = new StringBuffer(); - if (type.getKeys() != null && !type.getKeys().isEmpty()) { + if (!isNullOrEmpty(type.getKeys())) { if (type.getKeys().size() == 1) { Property key = type.getKeys().get(0); String keyName = key.getNormalizedName(); @@ -220,8 +222,7 @@ public String getKeyValue(EntityType type, Object entity) { + keyName.substring(0, 1).toUpperCase() + keyName.substring(1); try { - Method getter = entity.getClass().getDeclaredMethod( - getterName, (Class[]) null); + Method getter = entity.getClass().getDeclaredMethod(getterName, (Class[]) null); Object value = getter.invoke(entity, (Object[]) null); String strValue = TypeUtils.toEdmKey(value, key.getType()); if (strValue != null) { @@ -242,11 +243,9 @@ public String getKeyValue(EntityType type, Object entity) { + keyName.substring(0, 1).toUpperCase() + keyName.substring(1); try { - Method getter = entity.getClass().getDeclaredMethod( - getterName, (Class[]) null); + Method getter = entity.getClass().getDeclaredMethod(getterName, (Class[]) null); Object value = getter.invoke(entity, (Object[]) null); - String strValue = TypeUtils.toEdmKey(value, - key.getType()); + String strValue = TypeUtils.toEdmKey(value, key.getType()); if (strValue != null) { result.append(strValue); } else { diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java index 188f51abc4..67fe446c21 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/edm/TypeUtils.java @@ -31,10 +31,13 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.Objects; import org.restlet.Context; import org.restlet.engine.util.Base64; import org.restlet.engine.util.DateUtils; +import org.restlet.ext.odata.EdmConverter; +import org.restlet.ext.odata.JavaTypeHandler; import org.restlet.ext.odata.internal.reflect.ReflectUtils; /** @@ -65,6 +68,9 @@ public class TypeUtils { public static final NumberFormat timeFormat = DecimalFormat .getIntegerInstance(Locale.US); + private static EdmConverter edmConverter = new EdmConverter(); + private static JavaTypeHandler javaTypeHandler = new JavaTypeHandler(); + /** * Converts the String representation of the target WCF type to its * corresponding value. @@ -80,44 +86,7 @@ public static Object fromEdm(String value, String adoNetType) { return null; } - Object result = null; - try { - if (adoNetType.endsWith("Binary")) { - result = Base64.decode(value); - } else if (adoNetType.endsWith("Boolean")) { - result = Boolean.valueOf(value); - } else if (adoNetType.endsWith("DateTime")) { - result = DateUtils.parse(value, dateTimeFormats); - } else if (adoNetType.endsWith("DateTimeOffset")) { - result = DateUtils.parse(value, dateTimeFormats); - } else if (adoNetType.endsWith("Time")) { - result = timeFormat.parseObject(value); - } else if (adoNetType.endsWith("Decimal")) { - result = decimalFormat.parseObject(value); - } else if (adoNetType.endsWith("Single")) { - result = singleFormat.parseObject(value); - } else if (adoNetType.endsWith("Double")) { - result = doubleFormat.parseObject(value); - } else if (adoNetType.endsWith("Guid")) { - result = value; - } else if (adoNetType.endsWith("Int16")) { - result = Short.valueOf(value); - } else if (adoNetType.endsWith("Int32")) { - result = Integer.valueOf(value); - } else if (adoNetType.endsWith("Int64")) { - result = Long.valueOf(value); - } else if (adoNetType.endsWith("Byte")) { - result = Byte.valueOf(value); - } else if (adoNetType.endsWith("String")) { - result = value; - } - } catch (Exception e) { - Context.getCurrentLogger().warning( - "Cannot convert " + value + " from this EDM type " - + adoNetType); - } - - return result; + return edmConverter.fromEdm(value, adoNetType); } /** @@ -183,28 +152,7 @@ public static String getLiteralForm(String value, String adoNetType) { return null; } - String result = null; - try { - if (adoNetType.endsWith("Binary")) { - result = "'" + value + "'"; - } else if (adoNetType.endsWith("DateTime")) { - result = "datetime'" + value + "'"; - } else if (adoNetType.endsWith("DateTimeOffset")) { - result = "datetimeoffset'" + value + "'"; - } else if (adoNetType.endsWith("Time")) { - result = "time'" + value + "'"; - } else if (adoNetType.endsWith("Guid")) { - result = "guid'" + value + "'"; - } else if (adoNetType.endsWith("String")) { - result = "'" + value + "'"; - } - } catch (Exception e) { - Context.getCurrentLogger().warning( - "Cannot convert " + value + " from this EDM type " - + adoNetType); - } - - return result; + return edmConverter.getLiteralForm(value, adoNetType); } /** @@ -239,7 +187,29 @@ public static String getPackageName(String name) { } return builder.toString(); } + + /** + * Allows to specify a new Edm type converter. + * @param edmConverter + * The new Edm type converter. + */ + public static void registerEdmConverter(EdmConverter edmConverter) { + Objects.requireNonNull(edmConverter); + + TypeUtils.edmConverter = edmConverter; + } + /** + * Allows to specify a new Java type handler. + * @param javaTypeHandler + * The new Java type handler. + */ + public static void registerJavaTypeHandler(JavaTypeHandler javaTypeHandler) { + Objects.requireNonNull(javaTypeHandler); + + TypeUtils.javaTypeHandler = javaTypeHandler; + } + /** * Converts a value to the String representation of the target WCF type. * @@ -255,68 +225,7 @@ public static String toEdm(Object value, Type type) { return null; } - String result = null; - if (adoNetType.endsWith("Binary")) { - if ((byte[].class).isAssignableFrom(value.getClass())) { - result = toEdmBinary((byte[]) value); - } - } else if (adoNetType.endsWith("Boolean")) { - if ((Boolean.class).isAssignableFrom(value.getClass())) { - result = toEdmBoolean((Boolean) value); - } - } else if (adoNetType.endsWith("DateTime")) { - if ((Date.class).isAssignableFrom(value.getClass())) { - result = toEdmDateTime((Date) value); - } - } else if (adoNetType.endsWith("DateTimeOffset")) { - if ((Date.class).isAssignableFrom(value.getClass())) { - result = toEdmDateTime((Date) value); - } - } else if (adoNetType.endsWith("Time")) { - if ((Long.class).isAssignableFrom(value.getClass())) { - result = toEdmTime((Long) value); - } - } else if (adoNetType.endsWith("Decimal")) { - if ((Double.class).isAssignableFrom(value.getClass())) { - result = toEdmDecimal((Double) value); - } - } else if (adoNetType.endsWith("Single")) { - if ((Float.class).isAssignableFrom(value.getClass())) { - result = toEdmSingle((Float) value); - } else if ((Double.class).isAssignableFrom(value.getClass())) { - result = toEdmSingle((Double) value); - } - } else if (adoNetType.endsWith("Double")) { - if ((Double.class).isAssignableFrom(value.getClass())) { - result = toEdmDouble((Double) value); - } - } else if (adoNetType.endsWith("Guid")) { - result = value.toString(); - } else if (adoNetType.endsWith("Int16")) { - if ((Short.class).isAssignableFrom(value.getClass())) { - result = toEdmInt16((Short) value); - } - } else if (adoNetType.endsWith("Int32")) { - if ((Integer.class).isAssignableFrom(value.getClass())) { - result = toEdmInt32((Integer) value); - } - } else if (adoNetType.endsWith("Int64")) { - if ((Long.class).isAssignableFrom(value.getClass())) { - result = toEdmInt64((Long) value); - } - } else if (adoNetType.endsWith("Byte")) { - if ((Byte.class).isAssignableFrom(value.getClass())) { - result = toEdmByte((Byte) value); - } - } else if (adoNetType.endsWith("String")) { - result = value.toString(); - } - - if (result == null) { - result = value.toString(); - } - - return result; + return edmConverter.toEdm(value, type); } /** @@ -442,68 +351,7 @@ public static String toEdmKey(Object value, Type type) { return null; } - String result = null; - if (adoNetType.endsWith("Binary")) { - if ((byte[].class).isAssignableFrom(value.getClass())) { - result = toEdmBinary((byte[]) value); - } - } else if (adoNetType.endsWith("Boolean")) { - if ((Boolean.class).isAssignableFrom(value.getClass())) { - result = toEdmBoolean((Boolean) value); - } - } else if (adoNetType.endsWith("DateTime")) { - if ((Date.class).isAssignableFrom(value.getClass())) { - result = toEdmDateTime((Date) value); - } - } else if (adoNetType.endsWith("DateTimeOffset")) { - if ((Date.class).isAssignableFrom(value.getClass())) { - result = toEdmDateTime((Date) value); - } - } else if (adoNetType.endsWith("Time")) { - if ((Long.class).isAssignableFrom(value.getClass())) { - result = toEdmTime((Long) value); - } - } else if (adoNetType.endsWith("Decimal")) { - if ((Double.class).isAssignableFrom(value.getClass())) { - result = toEdmDecimal((Double) value); - } - } else if (adoNetType.endsWith("Single")) { - if ((Float.class).isAssignableFrom(value.getClass())) { - result = toEdmSingle((Float) value); - } else if ((Double.class).isAssignableFrom(value.getClass())) { - result = toEdmSingle((Double) value); - } - } else if (adoNetType.endsWith("Double")) { - if ((Double.class).isAssignableFrom(value.getClass())) { - result = toEdmDouble((Double) value); - } - } else if (adoNetType.endsWith("Guid")) { - result = value.toString(); - } else if (adoNetType.endsWith("Int16")) { - if ((Short.class).isAssignableFrom(value.getClass())) { - result = toEdmInt16((Short) value); - } - } else if (adoNetType.endsWith("Int32")) { - if ((Integer.class).isAssignableFrom(value.getClass())) { - result = toEdmInt32((Integer) value); - } - } else if (adoNetType.endsWith("Int64")) { - if ((Long.class).isAssignableFrom(value.getClass())) { - result = toEdmInt64((Long) value); - } - } else if (adoNetType.endsWith("Byte")) { - if ((Byte.class).isAssignableFrom(value.getClass())) { - result = toEdmByte((Byte) value); - } - } else if (adoNetType.endsWith("String")) { - result = "'" + value.toString() + "'"; - } - - if (result == null) { - result = value.toString(); - } - - return result; + return edmConverter.toEdmKey(value, type); } /** @@ -549,38 +397,7 @@ public static String toEdmTime(long value) { * @return The corresponding Java class or scalar type. */ public static Class toJavaClass(String edmTypeName) { - Class result = Object.class; - if (edmTypeName.endsWith("Binary")) { - result = byte[].class; - } else if (edmTypeName.endsWith("Boolean")) { - result = Boolean.class; - } else if (edmTypeName.endsWith("DateTime")) { - result = Date.class; - } else if (edmTypeName.endsWith("DateTimeOffset")) { - result = Date.class; - } else if (edmTypeName.endsWith("Time")) { - result = Long.class; - } else if (edmTypeName.endsWith("Decimal")) { - result = Double.class; - } else if (edmTypeName.endsWith("Single")) { - result = Double.class; - } else if (edmTypeName.endsWith("Double")) { - result = Double.class; - } else if (edmTypeName.endsWith("Guid")) { - result = String.class; - } else if (edmTypeName.endsWith("Int16")) { - result = Short.class; - } else if (edmTypeName.endsWith("Int32")) { - result = Integer.class; - } else if (edmTypeName.endsWith("Int64")) { - result = Long.class; - } else if (edmTypeName.endsWith("Byte")) { - result = Byte.class; - } else if (edmTypeName.endsWith("String")) { - result = String.class; - } - - return result; + return javaTypeHandler.toJavaClass(edmTypeName); } /** @@ -591,38 +408,7 @@ public static Class toJavaClass(String edmTypeName) { * @return The name of the corresponding Java class or scalar type. */ public static String toJavaTypeName(String edmTypeName) { - String result = "Object"; - if (edmTypeName.endsWith("Binary")) { - result = "byte[]"; - } else if (edmTypeName.endsWith("Boolean")) { - result = "boolean"; - } else if (edmTypeName.endsWith("DateTime")) { - result = "Date"; - } else if (edmTypeName.endsWith("DateTimeOffset")) { - result = "Date"; - } else if (edmTypeName.endsWith("Time")) { - result = "long"; - } else if (edmTypeName.endsWith("Decimal")) { - result = "double"; - } else if (edmTypeName.endsWith("Single")) { - result = "double"; - } else if (edmTypeName.endsWith("Double")) { - result = "double"; - } else if (edmTypeName.endsWith("Guid")) { - result = "String"; - } else if (edmTypeName.endsWith("Int16")) { - result = "short"; - } else if (edmTypeName.endsWith("Int32")) { - result = "int"; - } else if (edmTypeName.endsWith("Int64")) { - result = "long"; - } else if (edmTypeName.endsWith("Byte")) { - result = "byte"; - } else if (edmTypeName.endsWith("String")) { - result = "String"; - } - - return result; + return javaTypeHandler.toJavaTypeName(edmTypeName); } } diff --git a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java index fc34a1d449..181327f901 100644 --- a/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java +++ b/modules/org.restlet.ext.odata/src/org/restlet/ext/odata/internal/reflect/ReflectUtils.java @@ -43,6 +43,8 @@ import org.restlet.ext.odata.internal.edm.Property; import org.restlet.ext.odata.internal.edm.TypeUtils; +import static org.restlet.engine.util.CollectionsUtils.isNullOrEmpty; + /** * Handles Java reflection operations. * @@ -74,11 +76,9 @@ public class ReflectUtils { */ public static Class getEntryClass(Feed feed) { Class result = null; - if (feed != null && feed.getEntries() != null - && !feed.getEntries().isEmpty()) { + if (feed != null && !isNullOrEmpty(feed.getEntries())) { for (Entry entry : feed.getEntries()) { - if (entry.getCategories() != null - && !entry.getCategories().isEmpty()) { + if (!isNullOrEmpty(entry.getCategories())) { Category category = entry.getCategories().get(0); try { result = Class.forName(TypeUtils @@ -420,8 +420,7 @@ public static void setProperty(Object entity, Property property, String propertyValue) throws Exception { if (property.getType() != null) { invokeSetter(entity, property.getNormalizedName(), - TypeUtils.fromEdm(propertyValue, property.getType() - .getName())); + TypeUtils.fromEdm(propertyValue, property.getType().getName())); } } diff --git a/modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java b/modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java new file mode 100644 index 0000000000..eebef3108c --- /dev/null +++ b/modules/org.restlet/src/org/restlet/engine/util/CollectionsUtils.java @@ -0,0 +1,46 @@ +/** + * Copyright 2005-2014 Restlet + * + * The contents of this file are subject to the terms of one of the following + * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can + * select the license that you prefer but you may not use this file except in + * compliance with one of these Licenses. + * + * You can obtain a copy of the Apache 2.0 license at + * http://www.opensource.org/licenses/apache-2.0 + * + * You can obtain a copy of the EPL 1.0 license at + * http://www.opensource.org/licenses/eclipse-1.0 + * + * See the Licenses for the specific language governing permissions and + * limitations under the Licenses. + * + * Alternatively, you can obtain a royalty free commercial license with less + * limitations, transferable or non-transferable, directly at + * http://restlet.com/products/restlet-framework + * + * Restlet is a registered trademark of Restlet S.A.S. + */ + +package org.restlet.engine.util; + +import java.util.Collection; + +/** + * Util class for collections. + * + * @author Thierry Boileau + */ +public class CollectionsUtils { + + /** + * Indicates if the given collection is either null or empty. + * + * @param collection + * The collection. + * @return True if the collection is null of empty. + */ + public static boolean isNullOrEmpty(Collection collection) { + return collection == null || collection.isEmpty(); + } +}