/**
* 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.ext.odata.internal.edm;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import org.restlet.Context;
import org.restlet.engine.util.Base64;
import org.restlet.engine.util.DateUtils;
import org.restlet.ext.odata.internal.reflect.ReflectUtils;
/**
* Handle type operations.
*
* @author Thierry Boileau
*/
public class TypeUtils {
/** Formater for the EDM DateTime type. */
public static final List<String> dateTimeFormats = Arrays.asList(
"yyyy-MM-dd'T'HH:mm:ssz", "yyyy-MM-dd'T'HH:mm:ss",
"yyyy-MM-dd'T'HH:mm", "EEE, dd MMM yyyy HH:mm:ss zzz");
/** Formater for the EDM Decimal type. */
public static final NumberFormat decimalFormat = DecimalFormat
.getNumberInstance(Locale.US);
/** Formater for the EDM Double type. */
public static final NumberFormat doubleFormat = new DecimalFormat(
"0.###############", new DecimalFormatSymbols(Locale.US));
/** Formater for the EDM Single type. */
public static final NumberFormat singleFormat = new DecimalFormat(
"0.#######", new DecimalFormatSymbols(Locale.US));
/** Formater for the EDM Time type. */
public static final NumberFormat timeFormat = DecimalFormat
.getIntegerInstance(Locale.US);
/**
* 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 static 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 a correct full class name from the given name. Especially, it
* ensures that the first character of each sub package is in lower case.
*
* @param name
* The name.
* @return The package name extracted from the given name.
*/
public static String getFullClassName(String name) {
StringBuilder builder = new StringBuilder();
int index = name.lastIndexOf(".");
if (index > -1) {
builder.append(getPackageName(ReflectUtils.normalize(name
.substring(0, index))));
builder.append(name.substring(index));
} else {
builder.append(name);
}
return builder.toString();
}
/**
* Returns the Java class that corresponds to the given type according to
* the naming rules. It looks for the schema namespace name taken as the
* package name, then the name of this entity type is the class name.
*
* @param type
* The entity type.
* @return The Java class that corresponds to this type.
*/
public static Class<?> getJavaClass(EntityType type) {
Class<?> result = null;
String fullClassName = getPackageName(type.getSchema()) + "."
+ type.getClassName();
try {
result = Class.forName(fullClassName);
} catch (ClassNotFoundException e) {
Context.getCurrentLogger().warning(
"Can't find the following class in the class loader: "
+ fullClassName);
}
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 <a
* href="http://www.odata.org/docs/%5BMC-APDSU%5D.htm#z61934eae311a4af4b8f882c112248651">Abstract
* Type System</a>
*/
public static 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;
}
/**
* Returns the package name related to the given schema.
*
* @param schema
* The schema.
* @return The package name related to the given schema.
*/
public static String getPackageName(Schema schema) {
return getPackageName(schema.getNamespace().getName());
}
/**
* Returns a correct package name from the given name. Especially, it
* ensures that the first character of each sub package is in lower case.
*
* @param name
* The name.
* @return The package name extracted from the given name.
*/
public static String getPackageName(String name) {
StringBuilder builder = new StringBuilder();
String[] tab = name.split("\\.");
for (int i = 0; i < tab.length; i++) {
String string = tab[i];
if (i > 0) {
builder.append(".");
}
builder.append(string.toLowerCase());
}
return builder.toString();
}
/**
* 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 static 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;
}
/**
* Convert the given value to the String representation of a EDM Binary
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmBinary(byte[] value) {
return Base64.encode(value, false);
}
/**
* Convert the given value to the String representation of a EDM Boolean
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmBoolean(boolean value) {
return Boolean.toString(value);
}
/**
* Convert the given value to the String representation of a EDM Byte value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmByte(byte value) {
return Byte.toString(value);
}
/**
* Convert the given value to the String representation of a EDM DateTime
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmDateTime(Date value) {
return DateUtils.format(value, dateTimeFormats.get(0));
}
/**
* Convert the given value to the String representation of a EDM Decimal
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmDecimal(double value) {
return decimalFormat.format(value);
}
/**
* Convert the given value to the String representation of a EDM Double
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmDouble(double value) {
return doubleFormat.format(value);
}
/**
* Convert the given value to the String representation of a EDM Int16
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmInt16(short value) {
return Short.toString(value);
}
/**
* Convert the given value to the String representation of a EDM Int32
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmInt32(int value) {
return Integer.toString(value);
}
/**
* Convert the given value to the String representation of a EDM Int64
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmInt64(long value) {
return Long.toString(value);
}
/**
* 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 static 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;
}
/**
* Convert the given value to the String representation of a EDM Single
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmSingle(double value) {
return singleFormat.format(value);
}
/**
* Convert the given value to the String representation of a EDM Single
* value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmSingle(float value) {
return singleFormat.format(value);
}
/**
* Convert the given value to the String representation of a EDM Time value.
*
* @param value
* The value to convert.
* @return The value converted as String object.
*/
public static String toEdmTime(long value) {
return timeFormat.format(value);
}
/**
* Returns the corresponding Java class or scalar type.
*
* @param edmTypeName
* The type name.
* @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;
}
/**
* 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 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;
}
}