/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.axis2.databinding.types; // Consider removing this. // All operations behave as if BigIntegers were represented in two's-complement notation. // In its place, consider using primitive type long (which is already the right size) to hold the data. // This class can hide the fact that the data is stored in a signed entity, by careful implementation of the class' methods. import java.math.BigInteger; /** * Custom class for supporting primitive XSD data type UnsignedLong * * @see <a href="http://www.w3.org/TR/xmlschema-2/#unsignedLong">XML Schema 3.3.21</a> */ public class UnsignedLong extends java.lang.Number implements Comparable { private static final long serialVersionUID = -5919942584284897583L; protected BigInteger lValue = BigInteger.ZERO; private static BigInteger MAX = new BigInteger("18446744073709551615"); // max unsigned long public UnsignedLong() { } public UnsignedLong(double value) throws NumberFormatException { setValue(new BigInteger(Double.toString(value))); } public UnsignedLong(BigInteger value) throws NumberFormatException { setValue(value); } public UnsignedLong(long lValue) throws IllegalArgumentException { // new UnsignedLong( 0xffffffffffffffffL ) // should not throw any Exception because, as an UnsignedLong, it is in range and nonnegative. setValue(BigInteger.valueOf(lValue)); } public UnsignedLong(String stValue) throws NumberFormatException { // If stValue starts with a minus sign, that will be acceptable to the BigInteger constructor, // but it is not acceptable to us. // Once encoded into binary, it is too late to detect that the client intended a negative integer. // That detection must be performed here. try { if (stValue.charAt(0) == '\u002d') { throw new NumberFormatException( "A String that starts with a minus sign is not a valid representation of an UnsignedLong."); } setValue(new BigInteger(stValue)); } catch (NumberFormatException numberFormatException) { throw numberFormatException; } catch (IndexOutOfBoundsException indexOutOfBoundsException) { // This could happen if stValue is empty when we attempt to detect a minus sign. // From the client's point of view, the empty String should cause a NumberFormatException. throw new NumberFormatException( "An empty string is not a valid representation of an UnsignedLong."); } } private void setValue(BigInteger val) { if (!UnsignedLong.isValid(val)) { throw new IllegalArgumentException( // Messages.getMessage("badUnsignedLong00") + String.valueOf(val) + "]"); } this.lValue = val; } public static boolean isValid(BigInteger value) { // Converts this BigInteger to a long. // This conversion is analogous to a narrowing primitive conversion from long to int as defined in the Java Language Specification: // if this BigInteger is too big to fit in a long, only the low-order 64 bits are returned. // 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. long unsignedLongValue = value.longValue(); return !(compare(unsignedLongValue, BigInteger.ZERO.longValue()) < 0 || // less than zero compare(unsignedLongValue, MAX.longValue()) > 0); } public String toString() { return lValue.toString(); } public int hashCode() { if (lValue != null) return lValue.hashCode(); else return 0; } private Object __equalsCalc = null; public synchronized boolean equals(Object obj) { if (!(obj instanceof UnsignedLong)) return false; UnsignedLong other = (UnsignedLong)obj; if (this == obj) return true; if (__equalsCalc != null) { return (__equalsCalc == obj); } __equalsCalc = obj; boolean _equals; _equals = ((lValue == null && other.lValue == null) || (lValue != null && lValue.equals(other.lValue))); __equalsCalc = null; return _equals; } // Implement java.lang.Number interface public byte byteValue() { return lValue.byteValue(); } public short shortValue() { return lValue.shortValue(); } public int intValue() { return lValue.intValue(); } public long longValue() { return lValue.longValue(); } public double doubleValue() { return lValue.doubleValue(); } public float floatValue() { return lValue.floatValue(); } /** * @return the value 0 if the argument is an UnsignedLong numerically equal to this * UnsignedLong; a value less than 0 if the argument is an UnsignedLong numerically * greater than this UnsignedLong; and a value greater than 0 if the argument is an * UnsignedLong numerically less than this UnsignedLong. */ public int compareTo(Object o) { int retVal = 0; // arbitrary default value in case of exception; required return value in case this object is equal to the specified object if (o == null || !(o instanceof UnsignedLong)) { throw new ClassCastException("The argument is not an UnsignedLong."); } // Only need to change retVal if this object is not equal to the specified object. retVal = compare(longValue(), ((UnsignedLong)o).longValue()); return retVal; } /** * @return the value 0 if thatLong is a long numerically equal to thisLong; a value less than 0 * if thatLong is a long numerically greater than thisLong; and a value greater than 0 * if thatLong is a long numerically less than thisLong (unsigned comparison). */ private static int compare(long thisLong, long thatLong) { // To avoid infinite recursion, do not instantiate UnsignedLong in this method, which may be called during UnsignedLong instantiation. if (thisLong == thatLong) { return 0; } else { boolean isLessThan; // This is less than that. // Prepare the most significant half of the data for comparison. // The shift distance can be any number from 1 to 32 inclusive (1 is probably fastest). // 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). long thisHalfLong = (thisLong & 0xffffffff00000000L) >>> 1; long thatHalfLong = (thatLong & 0xffffffff00000000L) >>> 1; if (thisHalfLong == thatHalfLong) { // We must also look at the least significant half of the data. // Prepare the least significant half of the data for comparison. thisHalfLong = (thisLong & 0x00000000ffffffffL); thatHalfLong = (thatLong & 0x00000000ffffffffL); // We already know that the data is not equal. isLessThan = thisHalfLong < thatHalfLong; } else { // The answer is in the most significant half of the data. isLessThan = thisHalfLong < thatHalfLong; } if (isLessThan) { return -1; // Returns a negative integer as this object is less than than the specified object. } else { return 1; // Returns a positive integer as this object is greater than than the specified object. } } } }