[OLINGO-1393]Validate the values for a Decimal data type as per latest spec
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
index aa1fea5..1295c4d 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java
@@ -1275,7 +1275,7 @@
     entity.getProperties().add(getFactory().newPrimitiveProperty(PROPERTY_INT64,
         getFactory().newPrimitiveValueBuilder().buildInt64(Long.MAX_VALUE)));
     entity.getProperties().add(getFactory().newPrimitiveProperty(PROPERTY_DECIMAL,
-        getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(Long.MAX_VALUE))));
+        getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(922337203685477L))));
 
     final ODataEntityUpdateRequest<ClientEntity> requestUpdate = getEdmEnabledClient().getCUDRequestFactory()
         .getEntityUpdateRequest(uri, UpdateType.PATCH, entity);
@@ -1292,7 +1292,7 @@
     final ODataRetrieveResponse<ClientEntity> responseGet = requestGet.execute();
 
     assertEquals(Long.MAX_VALUE, responseGet.getBody().getProperty(PROPERTY_INT64).getPrimitiveValue().toValue());
-    assertEquals(BigDecimal.valueOf(Long.MAX_VALUE), responseGet.getBody().getProperty(PROPERTY_DECIMAL)
+    assertEquals(BigDecimal.valueOf(922337203685477L), responseGet.getBody().getProperty(PROPERTY_DECIMAL)
         .getPrimitiveValue()
         .toValue());
   }
@@ -1395,7 +1395,7 @@
                     .add(getFactory().newPrimitiveProperty(PROPERTY_INT64,
                         getFactory().newPrimitiveValueBuilder().buildInt64(Long.MIN_VALUE)))
                     .add(getFactory().newPrimitiveProperty(PROPERTY_DECIMAL,
-                        getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(12345678912L))))
+                        getFactory().newPrimitiveValueBuilder().buildDecimal(BigDecimal.valueOf(123456.78912))))
                     .add(getFactory().newPrimitiveProperty(PROPERTY_INT16,
                         getFactory().newPrimitiveValueBuilder().buildInt16((short) 2)))));
 
@@ -1413,7 +1413,7 @@
     final ClientComplexValue complexValue = responseGet.getBody().getComplexValue();
 
     assertEquals(Long.MIN_VALUE, complexValue.get(PROPERTY_INT64).getPrimitiveValue().toValue());
-    assertEquals(BigDecimal.valueOf(12345678912L), complexValue.get(PROPERTY_DECIMAL).getPrimitiveValue().toValue());
+    assertEquals(BigDecimal.valueOf(123456.78912), complexValue.get(PROPERTY_DECIMAL).getPrimitiveValue().toValue());
     assertEquals(2, complexValue.get(PROPERTY_INT16).getPrimitiveValue().toValue());
   }
 
@@ -1428,7 +1428,7 @@
     final ODataPropertyUpdateRequest requestUpdate = getEdmEnabledClient().getCUDRequestFactory()
         .getPropertyPrimitiveValueUpdateRequest(uri,
             getFactory().newPrimitiveProperty(PROPERTY_DECIMAL,
-                getFactory().newPrimitiveValueBuilder().buildInt64(Long.MAX_VALUE)));
+                getFactory().newPrimitiveValueBuilder().buildInt64(922337203685477L)));
 
     requestUpdate.setContentType(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE);
     requestUpdate.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE);
@@ -1441,7 +1441,7 @@
     requestGet.setAccept(CONTENT_TYPE_JSON_IEEE754_COMPATIBLE);
     final ODataRetrieveResponse<ClientProperty> responseGet = requestGet.execute();
 
-    assertEquals(BigDecimal.valueOf(Long.MAX_VALUE), responseGet.getBody().getPrimitiveValue().toValue());
+    assertEquals(BigDecimal.valueOf(922337203685477L), responseGet.getBody().getPrimitiveValue().toValue());
   }
 
   @Test
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java
index 8e4b6b5..ebe9cd7 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/EdmPrimitiveType.java
@@ -72,7 +72,7 @@
 public interface EdmPrimitiveType extends EdmType {
 
   String EDM_NAMESPACE = "Edm";
-
+  
   /**
    * Checks type compatibility.
    *
@@ -164,4 +164,20 @@
    * @throws EdmPrimitiveTypeException if a required prefix or required surrounding quotation marks are missing
    */
   String fromUriLiteral(String literal) throws EdmPrimitiveTypeException;
+  
+  /**
+   * Validates literal value for Decimal values in V4.01
+   *
+   * @param value the literal value
+   * @param isNullable whether the <code>null</code> value is allowed
+   * @param maxLength the maximum length
+   * @param precision the precision
+   * @param scale the scale (could be variable or floating)
+   * @param isUnicode whether non-ASCII characters are allowed (relevant only for Edm.String)
+   * @return <code>true</code> if the validation is successful
+   */
+  default boolean validateDecimals(String value, Boolean isNullable, Integer maxLength, 
+      Integer precision, String scale, Boolean isUnicode) {
+        return false;
+  }
 }
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java
index 8b9f8f9..e177d7d 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimal.java
@@ -83,8 +83,65 @@
 	}
     final int significantIntegerDigits = "0".equals(matcher.group(1)) ? 0 : matcher.group(1).length();
     final int decimals = matcher.group(2) == null ? 0 : matcher.group(2).length();
-    return (precision == null || precision >= significantIntegerDigits + decimals)
-        && (decimals <= (scale == null ? 0 : scale));
+    return (precision == null || (significantIntegerDigits >= 0 && 
+        significantIntegerDigits <= precision - ((scale == null) ? 0 : scale))) &&
+        (decimals >= 0 && decimals <= ((scale == null) ? 0 : scale));
+  }
+  
+  @Override
+  public boolean validateDecimals(final String value,
+      final Boolean isNullable, final Integer maxLength, final Integer precision,
+      final String scale, final Boolean isUnicode) {
+
+    return value == null
+        ? isNullable == null || isNullable
+        : validateLiteral(value) && validatePrecisionAndScale(value, precision, scale);
+  }
+
+  private boolean validatePrecisionAndScale(String value, Integer precision, String scale) {
+    Matcher matcher = PATTERN.matcher(value);
+    matcher.matches();
+    if (matcher.group(3) != null) {
+      String plainValue = new BigDecimal(value).toPlainString();
+      matcher = PATTERN.matcher(plainValue);
+      matcher.matches();
+    }
+    int significantIntegerDigits = "0".equals(matcher.group(1)) ? 0 : matcher.group(1).length();
+    int decimals = matcher.group(2) == null ? 0 : matcher.group(2).length();
+    
+    try {
+      int scaleValue = (scale == null) ? 0 : Integer.parseInt(scale);
+      return (precision == null || (significantIntegerDigits >= 0 && 
+          significantIntegerDigits <= precision - scaleValue)) &&
+          (decimals >= 0 && decimals <= scaleValue);
+    } catch(NumberFormatException e) {
+      String scaleValue = (scale == null) ? String.valueOf(0) : scale;
+      if (scaleValue.equals("variable")) {
+        return (precision == null || 
+            (significantIntegerDigits >= 0 && 
+            (significantIntegerDigits <= precision - decimals))) && 
+            (decimals >= 0 && decimals <= ((precision == null) ? 0 : precision));
+      } else if (scaleValue.equals("floating")) {
+        Matcher matcher1 = PATTERN.matcher(value);
+        matcher1.matches();
+        significantIntegerDigits = "0".equals(matcher1.group(1)) ? 0 : matcher1.group(1).length();
+        decimals = matcher1.group(2) == null ? 0 : matcher1.group(2).length();
+        int exponents = 0;
+        if (matcher1.group(3) != null) {
+          exponents = Integer.parseInt(matcher1.group(3).substring(1));
+          if (exponents < -95 || exponents > 96) {
+            if (String.valueOf(exponents).startsWith("-")) {
+              significantIntegerDigits += Integer.parseInt(String.valueOf(exponents + 95).substring(1));
+              exponents = -95;
+            }
+          }
+           return (significantIntegerDigits + decimals) <= 7 && (exponents >= -95 && exponents <= 96);
+        }
+      } else {
+        return false;
+      }
+    }
+    return false;
   }
 
   @Override
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java
index 3fb1c34..14ec110 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/EdmDecimalTest.java
@@ -19,6 +19,7 @@
 package org.apache.olingo.commons.core.edm.primitivetype;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.math.BigDecimal;
@@ -97,11 +98,10 @@
     assertEquals(Double.valueOf(0.5), instance.valueOfString("0.5", null, null, 1, 1, null, Double.class));
     assertEquals(Float.valueOf(0.5F), instance.valueOfString("0.5", null, null, null, 1, null, Float.class));
     assertEquals(new BigDecimal("12.3"), instance.valueOfString("12.3", null, null, 3, 1, null, BigDecimal.class));
-    assertEquals(new BigDecimal("31991163"), instance.valueOfString("3.1991163E7", null, null, 8, 7, 
-        null, BigDecimal.class));
     assertEquals(new BigDecimal("31991163.34"),
         instance.valueOfString("3.199116334E7", null, null, 10, 2, null, BigDecimal.class));
     
+    expectFacetsErrorInValueOfString(instance, "3.1991163E7", null, 8, 7, null, null);
     expectFacetsErrorInValueOfString(instance, "0.5", null, null, null, null, null);
     expectFacetsErrorInValueOfString(instance, "-1234", null, null, 2, null, null);
     expectFacetsErrorInValueOfString(instance, "1234", null, null, 3, null, null);
@@ -110,6 +110,9 @@
     expectFacetsErrorInValueOfString(instance, "12.34", null, null, 4, 1, null);
     expectFacetsErrorInValueOfString(instance, "0.00390625", null, null, 5, null, null);
     expectFacetsErrorInValueOfString(instance, "0.00390625", null, null, null, 7, null);
+    expectFacetsErrorInValueOfString(instance, "-129", null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+    expectFacetsErrorInValueOfString(instance, "-32769", null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null);
+    expectFacetsErrorInValueOfString(instance, "32768", null, null, Integer.MAX_VALUE, Integer.MAX_VALUE, null);
 
     expectContentErrorInValueOfString(instance, "1.");
     expectContentErrorInValueOfString(instance, ".1");
@@ -117,10 +120,6 @@
     expectContentErrorInValueOfString(instance, "1M");
     expectContentErrorInValueOfString(instance, "0x42");
 
-    expectUnconvertibleErrorInValueOfString(instance, "-129", Byte.class);
-    expectUnconvertibleErrorInValueOfString(instance, "128", Byte.class);
-    expectUnconvertibleErrorInValueOfString(instance, "-32769", Short.class);
-    expectUnconvertibleErrorInValueOfString(instance, "32768", Short.class);
     expectUnconvertibleErrorInValueOfString(instance, "-2147483649", Integer.class);
     expectUnconvertibleErrorInValueOfString(instance, "2147483648", Integer.class);
     expectUnconvertibleErrorInValueOfString(instance, "-9223372036854775809", Long.class);
@@ -130,4 +129,84 @@
 
     expectTypeErrorInValueOfString(instance, "1");
   }
+  
+  @Test
+  public void validateDecimal() throws Exception {
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("3.1991163E7", null, null, 8, 7, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("1", null, null, null, null, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("1.2", null, null, null, 0, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+    validate("10.2", false, null, 3, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("1.2", false, null, 3, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("0.12", false, null, 3, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("1.23", false, null, 3, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("1.03", false, null, 3, 2, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("1.03", false, null, 3, null, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("12", false, null, 3, null, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("12", false, null, null, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("0.12", false, null, null, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("12", false, null, null, null, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("0.12", false, null, null, null, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("0.23", false, null, 2, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("0.7", false, null, 2, 2, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("12e-101", false, null, 2, 2, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("12e101", false, null, 2, 2, null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("-1.234567e3", false, null, 7, 3, null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validate("0.7", false, null, 2, 3, null));
+  }
+  
+  @Test
+  public void validateDecimalInV401() throws Exception {
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("0.123", null, null, 3, "variable", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("1.23", null, null, 3, "variable", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("0.23", null, null, 3, "variable", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("0.7", null, null, 3, "variable", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("123", null, null, 3, "variable", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("12.3", null, null, 3, "variable", null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("12.34", null, null, 3, "variable", null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("1234", null, null, 3, "variable", null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("123.4", null, null, 3, "variable", null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("123.4", null, null, null, "variable", null));
+    
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("-1.234567e3", null, null, 7, "floating", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("1e-101", null, null, 7, "floating", null));
+    assertTrue(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("9.999999e96", null, null, 7, "floating", null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("1e-102", null, null, 7, "floating", null));
+    assertFalse(EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal).
+        validateDecimals("1e97", null, null, 7, "floating", null));
+    
+  }
 }
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
index 40152c9..5d5851c 100644
--- a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/edm/primitivetype/PrimitiveTypeBaseTest.java
@@ -85,7 +85,7 @@
 
   protected void expectUnconvertibleErrorInValueOfString(final EdmPrimitiveType instance, final String value,
       final Class<?> type) {
-    expectErrorInValueOfString(instance, value, true, Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE, true,
+    expectErrorInValueOfString(instance, value, true, Integer.MAX_VALUE, Integer.MAX_VALUE, null, true,
         type, "cannot be converted to");
   }