Source for org.jfree.data.xy.DefaultHighLowDataset

   1: /* ===========================================================
   2:  * JFreeChart : a free chart library for the Java(tm) platform
   3:  * ===========================================================
   4:  *
   5:  * (C) Copyright 2000-2008, by Object Refinery Limited and Contributors.
   6:  *
   7:  * Project Info:  http://www.jfree.org/jfreechart/index.html
   8:  *
   9:  * This library is free software; you can redistribute it and/or modify it
  10:  * under the terms of the GNU Lesser General Public License as published by
  11:  * the Free Software Foundation; either version 2.1 of the License, or
  12:  * (at your option) any later version.
  13:  *
  14:  * This library is distributed in the hope that it will be useful, but
  15:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  16:  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
  17:  * License for more details.
  18:  *
  19:  * You should have received a copy of the GNU Lesser General Public
  20:  * License along with this library; if not, write to the Free Software
  21:  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
  22:  * USA.
  23:  *
  24:  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
  25:  * in the United States and other countries.]
  26:  *
  27:  * --------------------------
  28:  * DefaultHighLowDataset.java
  29:  * --------------------------
  30:  * (C) Copyright 2002-2008, by Object Refinery Limited.
  31:  *
  32:  * Original Author:  David Gilbert (for Object Refinery Limited);
  33:  * Contributor(s):   -;
  34:  *
  35:  * Changes
  36:  * -------
  37:  * 21-Mar-2002 : Version 1 (DG);
  38:  * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
  39:  * 06-May-2004 : Now extends AbstractXYDataset and added new methods from
  40:  *               HighLowDataset (DG);
  41:  * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
  42:  *               getYValue() (DG);
  43:  * ------------- JFREECHART 1.0.x ---------------------------------------------
  44:  * 28-Nov-2006 : Added equals() method override (DG);
  45:  * 22-Apr-2008 : Implemented PublicCloneable (DG);
  46:  *
  47:  */
  48: 
  49: package org.jfree.data.xy;
  50: 
  51: import java.util.Arrays;
  52: import java.util.Date;
  53: 
  54: import org.jfree.util.PublicCloneable;
  55: 
  56: /**
  57:  * A simple implementation of the {@link OHLCDataset} interface.  See also
  58:  * the {@link DefaultOHLCDataset} class, which provides another implementation
  59:  * that is very similar.
  60:  */
  61: public class DefaultHighLowDataset extends AbstractXYDataset
  62:         implements OHLCDataset, PublicCloneable {
  63: 
  64:     /** The series key. */
  65:     private Comparable seriesKey;
  66: 
  67:     /** Storage for the dates. */
  68:     private Date[] date;
  69: 
  70:     /** Storage for the high values. */
  71:     private Number[] high;
  72: 
  73:     /** Storage for the low values. */
  74:     private Number[] low;
  75: 
  76:     /** Storage for the open values. */
  77:     private Number[] open;
  78: 
  79:     /** Storage for the close values. */
  80:     private Number[] close;
  81: 
  82:     /** Storage for the volume values. */
  83:     private Number[] volume;
  84: 
  85:     /**
  86:      * Constructs a new high/low/open/close dataset.
  87:      * <p>
  88:      * The current implementation allows only one series in the dataset.
  89:      * This may be extended in a future version.
  90:      *
  91:      * @param seriesKey  the key for the series (<code>null</code> not
  92:      *     permitted).
  93:      * @param date  the dates (<code>null</code> not permitted).
  94:      * @param high  the high values (<code>null</code> not permitted).
  95:      * @param low  the low values (<code>null</code> not permitted).
  96:      * @param open  the open values (<code>null</code> not permitted).
  97:      * @param close  the close values (<code>null</code> not permitted).
  98:      * @param volume  the volume values (<code>null</code> not permitted).
  99:      */
 100:     public DefaultHighLowDataset(Comparable seriesKey, Date[] date,
 101:             double[] high, double[] low, double[] open, double[] close,
 102:             double[] volume) {
 103: 
 104:         if (seriesKey == null) {
 105:             throw new IllegalArgumentException("Null 'series' argument.");
 106:         }
 107:         if (date == null) {
 108:             throw new IllegalArgumentException("Null 'date' argument.");
 109:         }
 110:         this.seriesKey = seriesKey;
 111:         this.date = date;
 112:         this.high = createNumberArray(high);
 113:         this.low = createNumberArray(low);
 114:         this.open = createNumberArray(open);
 115:         this.close = createNumberArray(close);
 116:         this.volume = createNumberArray(volume);
 117: 
 118:     }
 119: 
 120:     /**
 121:      * Returns the key for the series stored in this dataset.
 122:      *
 123:      * @param series  the index of the series (ignored, this dataset supports
 124:      *     only one series and this method always returns the key for series 0).
 125:      *
 126:      * @return The series key (never <code>null</code>).
 127:      */
 128:     public Comparable getSeriesKey(int series) {
 129:         return this.seriesKey;
 130:     }
 131: 
 132:     /**
 133:      * Returns the x-value for one item in a series.  The value returned is a
 134:      * <code>Long</code> instance generated from the underlying
 135:      * <code>Date</code> object.  To avoid generating a new object instance,
 136:      * you might prefer to call {@link #getXValue(int, int)}.
 137:      *
 138:      * @param series  the series (zero-based index).
 139:      * @param item  the item (zero-based index).
 140:      *
 141:      * @return The x-value.
 142:      *
 143:      * @see #getXValue(int, int)
 144:      * @see #getXDate(int, int)
 145:      */
 146:     public Number getX(int series, int item) {
 147:         return new Long(this.date[item].getTime());
 148:     }
 149: 
 150:     /**
 151:      * Returns the x-value for one item in a series, as a Date.
 152:      * <p>
 153:      * This method is provided for convenience only.
 154:      *
 155:      * @param series  the series (zero-based index).
 156:      * @param item  the item (zero-based index).
 157:      *
 158:      * @return The x-value as a Date.
 159:      *
 160:      * @see #getX(int, int)
 161:      */
 162:     public Date getXDate(int series, int item) {
 163:         return this.date[item];
 164:     }
 165: 
 166:     /**
 167:      * Returns the y-value for one item in a series.
 168:      * <p>
 169:      * This method (from the {@link XYDataset} interface) is mapped to the
 170:      * {@link #getCloseValue(int, int)} method.
 171:      *
 172:      * @param series  the series (zero-based index).
 173:      * @param item  the item (zero-based index).
 174:      *
 175:      * @return The y-value.
 176:      *
 177:      * @see #getYValue(int, int)
 178:      */
 179:     public Number getY(int series, int item) {
 180:         return getClose(series, item);
 181:     }
 182: 
 183:     /**
 184:      * Returns the high-value for one item in a series.
 185:      *
 186:      * @param series  the series (zero-based index).
 187:      * @param item  the item (zero-based index).
 188:      *
 189:      * @return The high-value.
 190:      *
 191:      * @see #getHighValue(int, int)
 192:      */
 193:     public Number getHigh(int series, int item) {
 194:         return this.high[item];
 195:     }
 196: 
 197:     /**
 198:      * Returns the high-value (as a double primitive) for an item within a
 199:      * series.
 200:      *
 201:      * @param series  the series (zero-based index).
 202:      * @param item  the item (zero-based index).
 203:      *
 204:      * @return The high-value.
 205:      *
 206:      * @see #getHigh(int, int)
 207:      */
 208:     public double getHighValue(int series, int item) {
 209:         double result = Double.NaN;
 210:         Number high = getHigh(series, item);
 211:         if (high != null) {
 212:             result = high.doubleValue();
 213:         }
 214:         return result;
 215:     }
 216: 
 217:     /**
 218:      * Returns the low-value for one item in a series.
 219:      *
 220:      * @param series  the series (zero-based index).
 221:      * @param item  the item (zero-based index).
 222:      *
 223:      * @return The low-value.
 224:      *
 225:      * @see #getLowValue(int, int)
 226:      */
 227:     public Number getLow(int series, int item) {
 228:         return this.low[item];
 229:     }
 230: 
 231:     /**
 232:      * Returns the low-value (as a double primitive) for an item within a
 233:      * series.
 234:      *
 235:      * @param series  the series (zero-based index).
 236:      * @param item  the item (zero-based index).
 237:      *
 238:      * @return The low-value.
 239:      *
 240:      * @see #getLow(int, int)
 241:      */
 242:     public double getLowValue(int series, int item) {
 243:         double result = Double.NaN;
 244:         Number low = getLow(series, item);
 245:         if (low != null) {
 246:             result = low.doubleValue();
 247:         }
 248:         return result;
 249:     }
 250: 
 251:     /**
 252:      * Returns the open-value for one item in a series.
 253:      *
 254:      * @param series  the series (zero-based index).
 255:      * @param item  the item (zero-based index).
 256:      *
 257:      * @return The open-value.
 258:      *
 259:      * @see #getOpenValue(int, int)
 260:      */
 261:     public Number getOpen(int series, int item) {
 262:         return this.open[item];
 263:     }
 264: 
 265:     /**
 266:      * Returns the open-value (as a double primitive) for an item within a
 267:      * series.
 268:      *
 269:      * @param series  the series (zero-based index).
 270:      * @param item  the item (zero-based index).
 271:      *
 272:      * @return The open-value.
 273:      *
 274:      * @see #getOpen(int, int)
 275:      */
 276:     public double getOpenValue(int series, int item) {
 277:         double result = Double.NaN;
 278:         Number open = getOpen(series, item);
 279:         if (open != null) {
 280:             result = open.doubleValue();
 281:         }
 282:         return result;
 283:     }
 284: 
 285:     /**
 286:      * Returns the close-value for one item in a series.
 287:      *
 288:      * @param series  the series (zero-based index).
 289:      * @param item  the item (zero-based index).
 290:      *
 291:      * @return The close-value.
 292:      *
 293:      * @see #getCloseValue(int, int)
 294:      */
 295:     public Number getClose(int series, int item) {
 296:         return this.close[item];
 297:     }
 298: 
 299:     /**
 300:      * Returns the close-value (as a double primitive) for an item within a
 301:      * series.
 302:      *
 303:      * @param series  the series (zero-based index).
 304:      * @param item  the item (zero-based index).
 305:      *
 306:      * @return The close-value.
 307:      *
 308:      * @see #getClose(int, int)
 309:      */
 310:     public double getCloseValue(int series, int item) {
 311:         double result = Double.NaN;
 312:         Number close = getClose(series, item);
 313:         if (close != null) {
 314:             result = close.doubleValue();
 315:         }
 316:         return result;
 317:     }
 318: 
 319:     /**
 320:      * Returns the volume-value for one item in a series.
 321:      *
 322:      * @param series  the series (zero-based index).
 323:      * @param item  the item (zero-based index).
 324:      *
 325:      * @return The volume-value.
 326:      *
 327:      * @see #getVolumeValue(int, int)
 328:      */
 329:     public Number getVolume(int series, int item) {
 330:         return this.volume[item];
 331:     }
 332: 
 333:     /**
 334:      * Returns the volume-value (as a double primitive) for an item within a
 335:      * series.
 336:      *
 337:      * @param series  the series (zero-based index).
 338:      * @param item  the item (zero-based index).
 339:      *
 340:      * @return The volume-value.
 341:      *
 342:      * @see #getVolume(int, int)
 343:      */
 344:     public double getVolumeValue(int series, int item) {
 345:         double result = Double.NaN;
 346:         Number volume = getVolume(series, item);
 347:         if (volume != null) {
 348:             result = volume.doubleValue();
 349:         }
 350:         return result;
 351:     }
 352: 
 353:     /**
 354:      * Returns the number of series in the dataset.
 355:      * <p>
 356:      * This implementation only allows one series.
 357:      *
 358:      * @return The number of series.
 359:      */
 360:     public int getSeriesCount() {
 361:         return 1;
 362:     }
 363: 
 364:     /**
 365:      * Returns the number of items in the specified series.
 366:      *
 367:      * @param series  the index (zero-based) of the series.
 368:      *
 369:      * @return The number of items in the specified series.
 370:      */
 371:     public int getItemCount(int series) {
 372:         return this.date.length;
 373:     }
 374: 
 375:     /**
 376:      * Tests this dataset for equality with an arbitrary instance.
 377:      *
 378:      * @param obj  the object (<code>null</code> permitted).
 379:      *
 380:      * @return A boolean.
 381:      */
 382:     public boolean equals(Object obj) {
 383:         if (obj == this) {
 384:             return true;
 385:         }
 386:         if (!(obj instanceof DefaultHighLowDataset)) {
 387:             return false;
 388:         }
 389:         DefaultHighLowDataset that = (DefaultHighLowDataset) obj;
 390:         if (!this.seriesKey.equals(that.seriesKey)) {
 391:             return false;
 392:         }
 393:         if (!Arrays.equals(this.date, that.date)) {
 394:             return false;
 395:         }
 396:         if (!Arrays.equals(this.open, that.open)) {
 397:             return false;
 398:         }
 399:         if (!Arrays.equals(this.high, that.high)) {
 400:             return false;
 401:         }
 402:         if (!Arrays.equals(this.low, that.low)) {
 403:             return false;
 404:         }
 405:         if (!Arrays.equals(this.close, that.close)) {
 406:             return false;
 407:         }
 408:         if (!Arrays.equals(this.volume, that.volume)) {
 409:             return false;
 410:         }
 411:         return true;
 412:     }
 413: 
 414:     /**
 415:      * Constructs an array of Number objects from an array of doubles.
 416:      *
 417:      * @param data  the double values to convert (<code>null</code> not
 418:      *     permitted).
 419:      *
 420:      * @return The data as an array of Number objects.
 421:      */
 422:     public static Number[] createNumberArray(double[] data) {
 423:         Number[] result = new Number[data.length];
 424:         for (int i = 0; i < data.length; i++) {
 425:             result[i] = new Double(data[i]);
 426:         }
 427:         return result;
 428:     }
 429: 
 430: }