001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.samples.daytrader.client; 018 019 import java.text.*; 020 import java.util.*; 021 import java.math.BigDecimal; 022 import javax.swing.table.*; 023 024 public class TradeQuoteAuditStats extends AbstractTableModel { 025 public static final int SYMBOL_COL = 0; 026 public static final int COMPANY_COL = 1; 027 public static final int PRICE_COL = 2; 028 public static final int AUDIT_PRICE_COL = 3; 029 public static final int VOLUME_COL = 4; 030 public static final int AUDIT_VOLUME_COL = 5; 031 public static final int OPEN_COL = 6; 032 public static final int LOW_COL = 7; 033 public static final int HIGH_COL = 8; 034 public static final int CHANGE_COL = 9; 035 public static final int UPDATE_COL = 10; 036 037 private static String columns[] = { 038 "Symbol", "Company Name", "Price", 039 "Audit Price", "Volume", "Audit Volume", 040 "Open", "Low", "High", 041 "Change", "Last Update"}; 042 043 private static Class columnClasses[] = { 044 String.class, String.class, String.class, 045 AuditModel.class, String.class, AuditModel.class, 046 String.class, String.class, String.class, 047 ChangeModel.class, String.class}; 048 049 private int numColumns = columns.length; 050 051 private NumberFormat nf; 052 private DateFormat df; 053 private Map map; 054 private ArrayList sortedList; 055 private Object lock; 056 private int lastSortCol = SYMBOL_COL; 057 private boolean lastSortForward = true; 058 059 public TradeQuoteAuditStats() { 060 init(); 061 } 062 063 public void init() { 064 map = new HashMap(); 065 sortedList = new ArrayList(); 066 nf = NumberFormat.getCurrencyInstance(); 067 df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); 068 lock = new Object(); 069 } 070 071 public void updateSymbol(String symbol, String company, BigDecimal newPrice, BigDecimal open, BigDecimal low, BigDecimal high, double volume, long publishTime, BigDecimal priceChange, double volumeChange) { 072 boolean newSymbol = false; 073 TradeStreamerQuoteDataBean bean; 074 075 synchronized(lock) { 076 bean = getSymbol(symbol); 077 if (bean == null) { // first time bean was used 078 bean = new TradeStreamerQuoteDataBean(); 079 bean.setSymbol(symbol); 080 bean.setCompanyName(company); 081 bean.setPrice(newPrice); 082 bean.setOpen(open); 083 bean.setLow(low); 084 bean.setHigh(high); 085 bean.setVolume(volume); 086 bean.setLastUpdate(new Date(publishTime)); 087 bean.setAuditPrice(priceChange); 088 bean.setAuditVolume(volumeChange); 089 bean.setChange(newPrice.subtract(open).doubleValue()); 090 newSymbol = true; 091 } 092 else { // update to an existing bean 093 bean.setPrice(newPrice); 094 bean.setOpen(open); 095 bean.setLow(low); 096 bean.setHigh(high); 097 bean.setVolume(volume); 098 bean.setLastUpdate(new Date(publishTime)); 099 bean.setAuditPrice((bean.getAuditPrice()).add(priceChange)); 100 bean.setAuditVolume(bean.getAuditVolume() + volumeChange); 101 bean.setChange(newPrice.subtract(open).doubleValue()); 102 } 103 104 map.put(symbol, bean); 105 106 if (newSymbol) { 107 sort(lastSortCol, false); 108 } 109 } 110 } 111 112 public TradeStreamerQuoteDataBean getSymbol(String symbol) { 113 synchronized(lock) { 114 TradeStreamerQuoteDataBean quote = (TradeStreamerQuoteDataBean)map.get(symbol); 115 return quote; 116 } 117 } 118 119 public TradeStreamerQuoteDataBean getSymbol(int row) { 120 synchronized(lock) { 121 Iterator it = sortedList.iterator(); 122 int ii = 0; 123 while (true) { 124 if (!it.hasNext()) { 125 break; 126 } 127 TradeStreamerQuoteDataBean bean = (TradeStreamerQuoteDataBean)it.next(); 128 if (ii == row) { 129 return bean; 130 } 131 ii++; 132 } 133 return null; 134 } 135 } 136 137 public void clearStats() { 138 synchronized(lock) { 139 init(); 140 } 141 } 142 143 public int getColumnCount() { 144 return numColumns; 145 } 146 147 public int getRowCount() { 148 synchronized(lock) { 149 return map.size(); 150 } 151 } 152 153 public Object getValueAt (int row, int column) { 154 synchronized(lock) { 155 Iterator it = sortedList.iterator(); 156 int ii = 0; 157 while (true) { 158 if (!it.hasNext()) { 159 break; 160 } 161 TradeStreamerQuoteDataBean bean = (TradeStreamerQuoteDataBean)it.next(); 162 double price; 163 if (ii == row) { 164 switch (column) { 165 case SYMBOL_COL: 166 return bean.getSymbol(); 167 case COMPANY_COL: 168 return bean.getCompanyName(); 169 case PRICE_COL: 170 price = bean.getPrice().doubleValue(); 171 return nf.format(price); 172 case AUDIT_PRICE_COL: 173 return bean.getAuditPriceModel(); 174 case VOLUME_COL: 175 return String.valueOf(bean.getVolume()); 176 case AUDIT_VOLUME_COL: 177 return bean.getAuditVolumeModel(); 178 case OPEN_COL: 179 price = bean.getOpen().doubleValue(); 180 return nf.format(price); 181 case LOW_COL: 182 price = bean.getLow().doubleValue(); 183 return nf.format(price); 184 case HIGH_COL: 185 price = bean.getHigh().doubleValue(); 186 return nf.format(price); 187 case CHANGE_COL: 188 return bean.getChangeModel(); 189 case UPDATE_COL: 190 Date update = bean.getLastUpdate(); 191 return df.format(update); 192 default: 193 break; 194 } 195 } 196 ii++; 197 } 198 return null; 199 } 200 } 201 202 public void setValueAt (Object aValue, int row, int column) { 203 // not editable 204 } 205 206 public String getColumnName(int columnIndex) { 207 return columns[columnIndex]; 208 } 209 210 public Class getColumnClass(int columnIndex) { 211 return columnClasses[columnIndex]; 212 } 213 214 public boolean isCellEditable(int row, int column) { 215 return false; 216 } 217 218 public void sort(int column, boolean fromUserGUI) { 219 synchronized(lock) { 220 Collection values = map.values(); 221 sortedList.clear(); 222 sortedList.addAll(values); 223 // TODO: be more carefull with obect allocation - make static comps? 224 Comparator comp = new TradeQuoteAuditStatsComparator(column); 225 Collections.sort(sortedList, comp); 226 if (fromUserGUI) { 227 if (column == lastSortCol) { 228 if (lastSortForward) { // if we already sorted forward, reverse 229 Collections.reverse(sortedList); 230 } 231 lastSortForward = !lastSortForward; // switch the last sort 232 } 233 } 234 lastSortCol = column; 235 } 236 } 237 }