/*
 This file is part of the software framework JStatCom, 
 a library for building applications for data based analysis.

 Copyright (C) 2000-2005  Markus Kraetzig

 This library is free software; you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as
 published by the Free Software Foundation; either version 2.1 of the
 License, or (at your option) any later version.

 This library is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
 */

package com.jstatcom.model;

import javolution37.javolution.xml.XmlElement;
import javolution37.javolution.xml.XmlFormat;

import com.jstatcom.util.UString;

/**
 * A number representation that conforms to the JSCData
 * interface. Numbers are stored as Double objects.
 * 

* Whenever the value of this data object changes, registered JSCDataListeners * are notified via a JSCDataEvent. If not otherwise stated, the * event objects always contain the values before the change and after * the change. *

* This class is thread-safe. All access to mutable data is synchronized. * All events are fired outside the synchronized blocks. * * @author Markus Kraetzig */ public final class JSCNumber extends AbstractJSCData { private final String name; private Double value = null; private JSCDataEvent clearEvent = null; private JSCDataEvent notEmptyEvent = null; /** * XML format field for (de)serialization. */ public static final XmlFormat JSCNumber_XML = new XmlFormat( JSCNumber.class) { public void format(JSCNumber data, XmlElement xml) { xml.setAttribute("name", data.name); synchronized (data) { xml.setAttribute("value", data.value + ""); } } public JSCNumber parse(XmlElement xml) { String nam = xml.getAttribute("name") + ""; String numberString = xml.getAttribute("value") + ""; Double newNumber = null; if (!numberString.equalsIgnoreCase("null")) newNumber = UString.parseToNumber(numberString); JSCNumber num = new JSCNumber(nam, newNumber); return num; } }; /** * Creates an empty JSCNumber. * * @param name the identifier of that object * @throws IllegalArgumentException if name is not valid * or if (name == null) * * @see com.jstatcom.model.JSCConstants#isValidName */ public JSCNumber(String name) { this(name, null); } /** * Creates a JSCNumber from value. * * @param name the identifier of that object * @param value the double to be used as value * @throws IllegalArgumentException if name is not valid * or if (name == null) * * @see com.jstatcom.model.JSCConstants#isValidName */ public JSCNumber(String name, double value) { this(name, new Double(value)); } /** * Creates a JSCNumber from value. * * @param name the identifier of that object * @param value the Double to be used as value * @throws IllegalArgumentException if name is not valid * or if (name == null) * * @see com.jstatcom.model.JSCConstants#isValidName */ public JSCNumber(String name, Double value) { super(); if (name == null) throw new IllegalArgumentException("Argument was null."); name = JSCConstants.checkNameThrowEx(name); this.name = name; this.value = value; } /** * Clears this data object. Fires: *

* if it was not empty before. After calling this * method isEmpty returns true. */ public void clear() { Double oldValue; synchronized (this) { if (value == null) // Nothing changes. return; oldValue = value; value = null; } // Dispatch event outside synchronized block. if (clearEvent == null) clearEvent = JSCDataEvent.valueOfEmptyState(this, true); if (eventSupport == null) return; getEventSupport().dispatchEvent(clearEvent); getEventSupport().dispatchEvent( JSCDataEvent.valueOfChanged(this, oldValue, null)); } /** * @see com.jstatcom.model.JSCData */ public synchronized JSCNumber copy() { return new JSCNumber(name, value); } /** * Gets the stored number as a double. * * @return the value as double * @throws IllegalStateException if object is empty */ public synchronized double doubleVal() { if (value == null) throw new IllegalStateException("JSCData is empty: " + toString() + "."); return value.doubleValue(); } /** * Gets the stored Double value. * * @return a Double or null if empty */ public synchronized Double getNumber() { return value; } /** * Gets the stored number as an int. * The following special int values are returned: * * Note that during this operation information is potentially lost. * Only the integer part is preserved, which is different from rounding. * * @return the result of getNumber().intValue() * @throws IllegalStateException if object is empty */ public synchronized int intVal() { if (value == null) throw new IllegalStateException("JSCData is empty: " + toString() + "."); return value.intValue(); } /** * Gets whether this is empty. This method returns true, * if value returns null. * * @return true if empty */ public synchronized boolean isEmpty() { return value == null; } /** * @see com.jstatcom.model.JSCData */ public synchronized boolean isEqual(JSCData o) { if (o == this) return true; if (!(o instanceof JSCNumber)) return false; JSCNumber otherNumber = (JSCNumber) o; boolean ret = true; synchronized (this) { synchronized (o) { if (value != null) ret = value.equals(otherNumber.getNumber()); else ret = otherNumber.getNumber() == null; } } return ret; } /** * Gets whether the value equals Double.NaN. * * @return true if this represents a missing value * @throws IllegalStateException if object is empty */ public synchronized boolean isNaN() { if (value == null) throw new IllegalStateException("JSCData is empty: " + toString() + "."); return Double.isNaN(value); } /** * @see com.jstatcom.model.JSCData */ public String name() { return name; } /** * Sets the value of this to newValue and fires * a JSCDataEvent of type: * * * @param newValue the new value */ public void setNumber(Double newValue) { if (newValue == null) { clear(); return; } boolean wasEmpty = false; Double oldValue = null; synchronized (this) { // Nothing changed. if (newValue.equals(value)) return; wasEmpty = isEmpty(); // No copy needed, because Double is immutable. oldValue = value; value = newValue; } // Dispatch event outside synchronized block. if (eventSupport == null) return; getEventSupport().dispatchEvent( JSCDataEvent.valueOfChanged(this, oldValue, newValue)); if (wasEmpty) { if (notEmptyEvent == null) notEmptyEvent = JSCDataEvent.valueOfEmptyState(this, false); getEventSupport().dispatchEvent(notEmptyEvent); } } /** * Sets the value of this to newDouble. Fires * a JSCDataEvent of type: * * * @param newDouble the new double */ public void setVal(double newDouble) { setNumber(new Double(newDouble)); } /** * Gets the type of this JSCData object. * * @return JSCTypes.NUMBER */ public JSCTypes type() { return JSCTypes.NUMBER; } /** * Gets the underlying value, which is stored as a Double. * * @return the value object or null if this is empty */ public synchronized Object value() { return value; } }

Ads help maintain this website.