/*
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.ts.TSDateRange;
/**
* Adapter to TSDateRange objects that conforms to the
* JSCData interface. Everytime something changes, a new
* TSDateRange object is created, because range objects are
* immutable.
*
* 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
* @see com.jstatcom.ts.TSDateRange
*/
public final class JSCDRange extends AbstractJSCData {
private final String name;
private TSDateRange tsRange;
private JSCDataEvent clearEvent = null;
private JSCDataEvent notEmptyEvent = null;
/**
* XML format field for (de)serialization.
*/
public static final XmlFormat JSCDRange_XML = new XmlFormat(
JSCDRange.class) {
public void format(JSCDRange data, XmlElement xml) {
xml.setAttribute("name", data.name);
synchronized (data) {
xml.setAttribute("value", data.tsRange + "");
}
}
public JSCDRange parse(XmlElement xml) {
String nam = xml.getAttribute("name") + "";
String rangeString = xml.getAttribute("value") + "";
TSDateRange newRange = null;
if (!rangeString.equalsIgnoreCase("null"))
newRange = TSDateRange.valueOf(rangeString);
return new JSCDRange(nam, newRange);
}
};
/**
* Creates an empty JSCDRange.
*
* @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 JSCDRange(String name) {
this(name, null);
}
/**
* Creates a JSCDRange for a given TSDateRange.
*
* @param name
* the identifier of that object
* @param tsRange
* the date value
* @throws IllegalArgumentException
* if name is not valid or
* if (name == null)
*
* @see com.jstatcom.model.JSCConstants#isValidName
*/
public JSCDRange(String name, TSDateRange tsRange) {
super();
if (name == null)
throw new IllegalArgumentException("Argument was null.");
name = JSCConstants.checkNameThrowEx(name);
this.name = name;
this.tsRange = tsRange;
}
/**
* Clears this data object. Fires:
*
* JSCDataEventTypes.EMPTY_STATE event
* JSCDataEventTypes.VALUE_CHANGED event
*
* if it was not empty before. After calling this method
* isEmpty returns true.
*/
public void clear() {
TSDateRange oldValue;
synchronized (this) {
if (tsRange == null) // Nothing changes.
return;
oldValue = tsRange;
tsRange = 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 JSCDRange copy() {
return new JSCDRange(name, tsRange);
}
/**
* Gets whether date is enclosed by this range.
*
* @param date
* the JSCDate to be checked
* @return true if date ist enclosed by
* this
* @throws IllegalArgumentException
* if (date == null) or
* if (date.isEmpty()) or
* if (isEmpty())
*/
public boolean encloses(JSCDate date) {
if (date == null)
throw new IllegalArgumentException("Argument was null.");
if (date.isEmpty())
throw new IllegalArgumentException("JSCDate arg is empty.");
synchronized (this) {
if (isEmpty())
throw new IllegalArgumentException("JSCDateRange is empty.");
return tsRange.encloses(date.getTSDate()) == null;
}
}
/**
* Gets whether dRange is enclosed by this range.
*
* @param dRange
* the JSCDRange to be checked
* @return true if dRange ist enclosed by
* this
* @throws IllegalArgumentException
* if (dRange == null) or
* if (dRange.isEmpty()) or
* if (isEmpty())
*/
public boolean encloses(JSCDRange dRange) {
if (dRange == null)
throw new IllegalArgumentException("Argument was null.");
if (dRange.isEmpty())
throw new IllegalArgumentException("JSCDRange arg is empty.");
synchronized (this) {
if (isEmpty())
throw new IllegalArgumentException("JSCDRange is empty.");
return tsRange.encloses(dRange.getTSDateRange()) == null;
}
}
/**
* Gets the stored date object.
*
* @return the used TSDateRange or null if
* empty
*/
public synchronized TSDateRange getTSDateRange() {
return tsRange;
}
/**
* Gets whether this is empty. This method returns
* true, if value returns null.
*
* @return true if empty
*/
public synchronized boolean isEmpty() {
return tsRange == null;
}
/**
* @see com.jstatcom.model.JSCData
*/
public boolean isEqual(JSCData o) {
if (o == this)
return true;
if (!(o instanceof JSCDRange))
return false;
JSCDRange otherRange = (JSCDRange) o;
boolean ret = true;
synchronized (this) {
synchronized (o) {
if (tsRange != null)
ret = tsRange.equals(otherRange.getTSDateRange());
else
ret = otherRange.getTSDateRange() == null;
}
}
return ret;
}
/**
* @see com.jstatcom.model.JSCData
*/
public String name() {
return name;
}
/**
* Sets a new value to this date adapter. Fires a JSCDataEvent
* of type:
*
* JSCDataEventTypes.VALUE_CHANGED if
* !newRange.equals(getTSDateRange())
* JSCDataEventTypes.EMPTY_STATE if
* newRange != null and this was empty before
* JSCDataEventTypes.EMPTY_STATE if
* newRange == null and this was not empty before
*
*
* @param newRange
* the new range, if null it is similar to
* clear
*/
public void setVal(TSDateRange newRange) {
if (newRange == null) {
clear();
return;
}
boolean wasEmpty = false;
TSDateRange oldValue = null;
synchronized (this) {
// Nothing changed.
if (newRange.equals(tsRange))
return;
wasEmpty = isEmpty();
// No copy needed, because TSDateRange is immutable.
oldValue = tsRange;
tsRange = newRange;
}
// Dispatch event outside synchronized block.
if (eventSupport == null)
return;
getEventSupport().dispatchEvent(
JSCDataEvent.valueOfChanged(this, oldValue, newRange));
if (wasEmpty) {
if (notEmptyEvent == null)
notEmptyEvent = JSCDataEvent.valueOfEmptyState(this, false);
getEventSupport().dispatchEvent(notEmptyEvent);
}
}
/**
* Gets the type of this JSCData object.
*
* @return JSCTypes.DRANGE
*/
public JSCTypes type() {
return JSCTypes.DRANGE;
}
/**
* Gets the underlying value, which is stored as a TSDateRange.
*
* @return the value object or null if this is
* empty
*/
public synchronized Object value() {
return tsRange;
}
}
Ads help maintain this website.