001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */
019: package org.apache.axis2.databinding.types;
020:
021: // Consider removing this.
022: // All operations behave as if BigIntegers were represented in two's-complement notation.
023: // In its place, consider using primitive type long (which is already the right size) to hold the data.
024: // This class can hide the fact that the data is stored in a signed entity, by careful implementation of the class' methods.
025:
026: import java.math.BigInteger;
027:
028: /**
029: * Custom class for supporting primitive XSD data type UnsignedLong
030: *
031: * @see <a href="http://www.w3.org/TR/xmlschema-2/#unsignedLong">XML Schema 3.3.21</a>
032: */
033: public class UnsignedLong extends java.lang.Number implements
034: Comparable {
035:
036: private static final long serialVersionUID = -5919942584284897583L;
037:
038: protected BigInteger lValue = BigInteger.ZERO;
039: private static BigInteger MAX = new BigInteger(
040: "18446744073709551615"); // max unsigned long
041:
042: public UnsignedLong() {
043: }
044:
045: public UnsignedLong(double value) throws NumberFormatException {
046: setValue(new BigInteger(Double.toString(value)));
047: }
048:
049: public UnsignedLong(BigInteger value) throws NumberFormatException {
050: setValue(value);
051: }
052:
053: public UnsignedLong(long lValue) throws IllegalArgumentException {
054: // new UnsignedLong( 0xffffffffffffffffL )
055: // should not throw any Exception because, as an UnsignedLong, it is in range and nonnegative.
056: setValue(BigInteger.valueOf(lValue));
057: }
058:
059: public UnsignedLong(String stValue) throws NumberFormatException {
060:
061: // If stValue starts with a minus sign, that will be acceptable to the BigInteger constructor,
062: // but it is not acceptable to us.
063: // Once encoded into binary, it is too late to detect that the client intended a negative integer.
064: // That detection must be performed here.
065: try {
066: if (stValue.charAt(0) == '\u002d') {
067: throw new NumberFormatException(
068: "A String that starts with a minus sign is not a valid representation of an UnsignedLong.");
069: }
070: setValue(new BigInteger(stValue));
071: }
072:
073: catch (NumberFormatException numberFormatException) {
074: throw numberFormatException;
075: }
076:
077: catch (IndexOutOfBoundsException indexOutOfBoundsException) {
078: // This could happen if stValue is empty when we attempt to detect a minus sign.
079: // From the client's point of view, the empty String should cause a NumberFormatException.
080: throw new NumberFormatException(
081: "An empty string is not a valid representation of an UnsignedLong.");
082: }
083:
084: }
085:
086: private void setValue(BigInteger val) {
087: if (!UnsignedLong.isValid(val)) {
088: throw new IllegalArgumentException(
089: // Messages.getMessage("badUnsignedLong00") +
090: String.valueOf(val) + "]");
091: }
092: this .lValue = val;
093: }
094:
095: public static boolean isValid(BigInteger value) {
096:
097: // Converts this BigInteger to a long.
098: // This conversion is analogous to a narrowing primitive conversion from long to int as defined in the Java Language Specification:
099: // if this BigInteger is too big to fit in a long, only the low-order 64 bits are returned.
100: // Note that this conversion can lose information about the overall magnitude of the BigInteger value as well as return a result with the opposite sign.
101: long unsignedLongValue = value.longValue();
102:
103: return !(compare(unsignedLongValue, BigInteger.ZERO.longValue()) < 0 || // less than zero
104: compare(unsignedLongValue, MAX.longValue()) > 0);
105: }
106:
107: public String toString() {
108: return lValue.toString();
109: }
110:
111: public int hashCode() {
112: if (lValue != null)
113: return lValue.hashCode();
114: else
115: return 0;
116: }
117:
118: private Object __equalsCalc = null;
119:
120: public synchronized boolean equals(Object obj) {
121: if (!(obj instanceof UnsignedLong))
122: return false;
123: UnsignedLong other = (UnsignedLong) obj;
124: if (this == obj)
125: return true;
126: if (__equalsCalc != null) {
127: return (__equalsCalc == obj);
128: }
129: __equalsCalc = obj;
130: boolean _equals;
131: _equals = ((lValue == null && other.lValue == null) || (lValue != null && lValue
132: .equals(other.lValue)));
133: __equalsCalc = null;
134: return _equals;
135: }
136:
137: // Implement java.lang.Number interface
138: public byte byteValue() {
139: return lValue.byteValue();
140: }
141:
142: public short shortValue() {
143: return lValue.shortValue();
144: }
145:
146: public int intValue() {
147: return lValue.intValue();
148: }
149:
150: public long longValue() {
151: return lValue.longValue();
152: }
153:
154: public double doubleValue() {
155: return lValue.doubleValue();
156: }
157:
158: public float floatValue() {
159: return lValue.floatValue();
160: }
161:
162: /**
163: * @return the value 0 if the argument is an UnsignedLong numerically equal to this
164: * UnsignedLong; a value less than 0 if the argument is an UnsignedLong numerically
165: * greater than this UnsignedLong; and a value greater than 0 if the argument is an
166: * UnsignedLong numerically less than this UnsignedLong.
167: */
168: public int compareTo(Object o) {
169: int retVal = 0; // arbitrary default value in case of exception; required return value in case this object is equal to the specified object
170:
171: if (o == null || !(o instanceof UnsignedLong)) {
172: throw new ClassCastException(
173: "The argument is not an UnsignedLong.");
174: }
175: // Only need to change retVal if this object is not equal to the specified object.
176: retVal = compare(longValue(), ((UnsignedLong) o).longValue());
177:
178: return retVal;
179:
180: }
181:
182: /**
183: * @return the value 0 if thatLong is a long numerically equal to thisLong; a value less than 0
184: * if thatLong is a long numerically greater than thisLong; and a value greater than 0
185: * if thatLong is a long numerically less than thisLong (unsigned comparison).
186: */
187: private static int compare(long this Long, long thatLong) {
188: // To avoid infinite recursion, do not instantiate UnsignedLong in this method, which may be called during UnsignedLong instantiation.
189:
190: if (this Long == thatLong) {
191: return 0;
192: } else {
193: boolean isLessThan; // This is less than that.
194:
195: // Prepare the most significant half of the data for comparison.
196: // The shift distance can be any number from 1 to 32 inclusive (1 is probably fastest).
197: // A shift distance of one is sufficient to move the significant data off of the sign bit, allowing for a signed comparison of positive numbers (i.e. an unsigned comparison).
198: long this HalfLong = (this Long & 0xffffffff00000000L) >>> 1;
199: long thatHalfLong = (thatLong & 0xffffffff00000000L) >>> 1;
200:
201: if (this HalfLong == thatHalfLong) {
202: // We must also look at the least significant half of the data.
203:
204: // Prepare the least significant half of the data for comparison.
205: this HalfLong = (this Long & 0x00000000ffffffffL);
206: thatHalfLong = (thatLong & 0x00000000ffffffffL);
207:
208: // We already know that the data is not equal.
209: isLessThan = this HalfLong < thatHalfLong;
210: } else {
211: // The answer is in the most significant half of the data.
212: isLessThan = this HalfLong < thatHalfLong;
213: }
214:
215: if (isLessThan) {
216: return -1; // Returns a negative integer as this object is less than than the specified object.
217: } else {
218: return 1; // Returns a positive integer as this object is greater than than the specified object.
219: }
220: }
221: }
222:
223: }
|