1 /* Copyright 2004 The Apache Software Foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 package org.apache.xmlbeans.impl.values;
17
18 import org.apache.xmlbeans.SchemaType;
19 import org.apache.xmlbeans.XmlErrorCodes;
20 import org.apache.xmlbeans.XmlObject;
21 import org.apache.xmlbeans.impl.common.ValidationContext;
22 import org.apache.xmlbeans.impl.common.QNameHelper;
23
24
25 import java.math.BigDecimal;
26
27 public abstract class JavaDecimalHolderEx extends JavaDecimalHolder
28 {
29 private SchemaType _schemaType;
30
31 public SchemaType schemaType()
32 { return _schemaType; }
33
34 public JavaDecimalHolderEx(SchemaType type, boolean complex)
35 { _schemaType = type; initComplexType(complex, false); }
36
37 protected void set_text(String s)
38 {
39 if (_validateOnSet())
40 validateLexical(s, _schemaType, _voorVc);
41
42 BigDecimal v = null;
43 try {
44 v = new BigDecimal(s);
45 }
46 catch (NumberFormatException e)
47 {
48 _voorVc.invalid(XmlErrorCodes.DECIMAL, new Object[] { s });
49 }
50
51 if (_validateOnSet())
52 validateValue(v, _schemaType, _voorVc);
53
54 super.set_BigDecimal(v);
55 }
56
57 protected void set_BigDecimal(BigDecimal v)
58 {
59 if (_validateOnSet())
60 validateValue(v, _schemaType, _voorVc);
61 super.set_BigDecimal(v);
62 }
63
64 public static void validateLexical(String v, SchemaType sType, ValidationContext context)
65 {
66 JavaDecimalHolder.validateLexical(v, context);
67
68 // check pattern
69 if (sType.hasPatternFacet())
70 {
71 if (!sType.matchPatternFacet(v))
72 {
73 // TODO - describe string and pattern here in error
74 context.invalid(XmlErrorCodes.DATATYPE_VALID$PATTERN_VALID,
75 new Object[] { "decimal", v, QNameHelper.readable(sType) });
76 }
77 }
78 }
79
80 /**
81 * Performs facet validation only.
82 */
83
84 public static void validateValue(BigDecimal v, SchemaType sType, ValidationContext context)
85 {
86 // fractional digits
87 XmlObject fd = sType.getFacet(SchemaType.FACET_FRACTION_DIGITS);
88 if (fd != null)
89 {
90 int scale = ((XmlObjectBase)fd).bigIntegerValue().intValue();
91 try
92 {
93 // used only for side-effect - this does not change v despite
94 // the name of the method
95 v.setScale(scale);
96 }
97 catch(ArithmeticException e)
98 {
99 // ArithmeticException will be thrown if cannot represent as an Integer
100 // with this scale - i.e. would need a fraction which would correspond
101 // to digits beyond the allowed number
102 context.invalid(XmlErrorCodes.DATATYPE_FRACTION_DIGITS_VALID,
103 new Object[] { new Integer(v.scale()), v.toString(), new Integer(scale), QNameHelper.readable(sType) });
104 return;
105 }
106 }
107
108 // total digits
109 XmlObject td = sType.getFacet(SchemaType.FACET_TOTAL_DIGITS);
110 if (td != null)
111 {
112 String temp = v.unscaledValue().toString();
113 int tdf = ((XmlObjectBase)td).bigIntegerValue().intValue();
114 int origLen = temp.length();
115 int len = origLen;
116 if (origLen > 0)
117 {
118 // don't count leading minus
119 if (temp.charAt(0) == '-')
120 {
121 len -= 1;
122 }
123
124 // don't count trailing zeros if we can absorb them into scale
125 int insignificantTrailingZeros = 0;
126 int vScale = v.scale();
127 for(int j = origLen-1;
128 temp.charAt(j) == '0' && j > 0 && insignificantTrailingZeros < vScale;
129 j--)
130 {
131 insignificantTrailingZeros++;
132 }
133
134 len -= insignificantTrailingZeros;
135 }
136
137 if (len > tdf)
138 {
139 context.invalid(XmlErrorCodes.DATATYPE_TOTAL_DIGITS_VALID,
140 new Object[] { new Integer(len), v.toString(), new Integer(tdf), QNameHelper.readable(sType) });
141 return;
142 }
143 }
144
145 // min ex
146 XmlObject mine = sType.getFacet(SchemaType.FACET_MIN_EXCLUSIVE);
147 if (mine != null)
148 {
149 BigDecimal m = ((XmlObjectBase)mine).bigDecimalValue();
150 if (v.compareTo(m) <= 0)
151 {
152 context.invalid(XmlErrorCodes.DATATYPE_MIN_EXCLUSIVE_VALID,
153 new Object[] { "decimal", v, m, QNameHelper.readable(sType) });
154 return;
155 }
156 }
157
158 // min in
159 XmlObject mini = sType.getFacet(SchemaType.FACET_MIN_INCLUSIVE);
160 if (mini != null)
161 {
162 BigDecimal m = ((XmlObjectBase)mini).bigDecimalValue();
163 if (v.compareTo(m) < 0)
164 {
165 context.invalid(XmlErrorCodes.DATATYPE_MIN_INCLUSIVE_VALID,
166 new Object[] { "decimal", v, m, QNameHelper.readable(sType) });
167 return;
168 }
169 }
170
171 // max in
172 XmlObject maxi = sType.getFacet(SchemaType.FACET_MAX_INCLUSIVE);
173 if (maxi != null)
174 {
175 BigDecimal m = ((XmlObjectBase)maxi).bigDecimalValue();
176 if (v.compareTo(m) > 0)
177 {
178 context.invalid(XmlErrorCodes.DATATYPE_MAX_INCLUSIVE_VALID,
179 new Object[] { "decimal", v, m, QNameHelper.readable(sType) });
180 return;
181 }
182 }
183
184 // max ex
185 XmlObject maxe = sType.getFacet(SchemaType.FACET_MAX_EXCLUSIVE);
186 if (maxe != null)
187 {
188 BigDecimal m = ((XmlObjectBase)maxe).bigDecimalValue();
189 if (v.compareTo(m) >= 0)
190 {
191 context.invalid(XmlErrorCodes.DATATYPE_MAX_EXCLUSIVE_VALID,
192 new Object[] { "decimal", v, m, QNameHelper.readable(sType) });
193 return;
194 }
195 }
196
197 // enumeration
198 XmlObject[] vals = sType.getEnumerationValues();
199 if (vals != null)
200 {
201 for (int i = 0; i < vals.length; i++)
202 if (v.equals(((XmlObjectBase)vals[i]).bigDecimalValue()))
203 return;
204 context.invalid(XmlErrorCodes.DATATYPE_ENUM_VALID,
205 new Object[] { "decimal", v, QNameHelper.readable(sType) });
206 }
207 }
208
209 protected void validate_simpleval(String lexical, ValidationContext ctx)
210 {
211 validateLexical(lexical, schemaType(), ctx);
212 validateValue(bigDecimalValue(), schemaType(), ctx);
213 }
214
215 }