001 /**
002 * Copyright 2007 Mike Kroutikov.
003 *
004 * This program is free software; you can redistribute it and/or modify
005 * it under the terms of the Lesser GNU General Public License as
006 * published by the Free Software Foundation; either version 3 of
007 * the License, or (at your option) any later version.
008 *
009 * This program is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012 * Lesser GNU General Public License for more details.
013 *
014 * You should have received a copy of the Lesser GNU General Public License
015 * along with this program. If not, see <http://www.gnu.org/licenses/>.
016 */
017
018 package org.otfeed.protocol.request;
019
020 import org.otfeed.event.ICompletionDelegate;
021 import org.otfeed.event.IDataDelegate;
022 import org.otfeed.event.OTBookCancel;
023 import org.otfeed.event.OTBookChange;
024 import org.otfeed.event.OTBookDelete;
025 import org.otfeed.event.OTBookExecute;
026 import org.otfeed.event.OTBookOrder;
027 import org.otfeed.event.OTBookPriceLevel;
028 import org.otfeed.event.OTBookPurge;
029 import org.otfeed.event.OTBookReplace;
030 import org.otfeed.protocol.CommandEnum;
031 import org.otfeed.protocol.DataEnum;
032 import org.otfeed.protocol.ProtocolException;
033
034 import org.otfeed.protocol.request.book.BookReader;
035
036 import java.nio.ByteBuffer;
037
038 import java.util.Date;
039 import java.util.Map;
040 import java.util.HashMap;
041
042 /**
043 * Request to receive historical book events.
044 */
045 public final class HistBookRequest extends AbstractSessionRequest {
046
047 private final String exchangeCode;
048 private final String symbolCode;
049 private final Date startDate;
050 private final Date endDate;
051 private final int mask;
052
053 private final Map<Integer,BookReader> map = new HashMap<Integer,BookReader>();
054
055 public String getExchangeCode() { return exchangeCode; }
056 public String getSymbolCode() { return symbolCode; }
057 public Date getStartDate() { return startDate; }
058 public Date getEndDate() { return endDate; }
059
060 public HistBookRequest(int requestId,
061 String exchangeCode,
062 String symbolCode,
063 Date startDate,
064 Date endDate,
065 IDataDelegate<OTBookOrder> orderDelegate,
066 IDataDelegate<OTBookChange> changeDelegate,
067 IDataDelegate<OTBookReplace> replaceDelegate,
068 IDataDelegate<OTBookCancel> cancelDelegate,
069 IDataDelegate<OTBookPurge> purgeDelegate,
070 IDataDelegate<OTBookExecute> executeDelegate,
071 IDataDelegate<OTBookDelete> deleteDelegate,
072 IDataDelegate<OTBookPriceLevel> priceLevelDelegate,
073 ICompletionDelegate completionDelegate) {
074
075 super(CommandEnum.REQUEST_HIST_BOOKS,
076 requestId, completionDelegate);
077
078 Check.notNull(exchangeCode, "exchangeCode");
079 Check.notNull(symbolCode, "symbolCode");
080 Check.notNull(startDate, "startDate");
081 Check.notNull(endDate, "endDate");
082
083 this.exchangeCode = exchangeCode;
084 this.symbolCode = symbolCode;
085 this.startDate = startDate;
086 this.endDate = endDate;
087
088 int mask = 0;
089 if(orderDelegate != null) {
090 BookReader rdr = BookReader.orderReader(orderDelegate);
091 map.put(rdr.type.code, rdr);
092 mask |= rdr.mask;
093 }
094 if(changeDelegate != null) {
095 BookReader rdr = BookReader.changeReader(changeDelegate);
096 map.put(rdr.type.code, rdr);
097 mask |= rdr.mask;
098 }
099 if(replaceDelegate != null) {
100 BookReader rdr = BookReader.replaceReader(replaceDelegate);
101 map.put(rdr.type.code, rdr);
102 mask |= rdr.mask;
103 }
104 if(cancelDelegate != null) {
105 BookReader rdr = BookReader.cancelReader(cancelDelegate);
106 map.put(rdr.type.code, rdr);
107 mask |= rdr.mask;
108 }
109 if(purgeDelegate != null) {
110 BookReader rdr = BookReader.purgeReader(purgeDelegate);
111 map.put(rdr.type.code, rdr);
112 mask |= rdr.mask;
113 }
114 if(executeDelegate != null) {
115 BookReader rdr = BookReader.executeReader(executeDelegate);
116 map.put(rdr.type.code, rdr);
117 mask |= rdr.mask;
118 }
119 if(deleteDelegate != null) {
120 BookReader rdr = BookReader.deleteReader(deleteDelegate);
121 map.put(rdr.type.code, rdr);
122 mask |= rdr.mask;
123 }
124 if(priceLevelDelegate != null) {
125 BookReader rdr = BookReader.priceLevelReader(priceLevelDelegate);
126 map.put(rdr.type.code, rdr);
127 mask |= rdr.mask;
128 }
129
130 if(mask == 0) {
131 throw new IllegalArgumentException("you must set one of the book event delegates");
132 }
133
134 this.mask = mask;
135 }
136
137 @Override
138 public void writeRequest(ByteBuffer out) {
139 super.writeRequest(out);
140
141 Util.writeString(out, exchangeCode, 15);
142 Util.writeString(out, symbolCode, 15);
143 Util.writeDate(out, startDate);
144 Util.writeDate(out, endDate);
145 out.putInt(mask);
146 }
147
148 @Override
149 public JobStatus handleMessage(Header header, ByteBuffer in) {
150 super.handleMessage(header, in);
151
152 int count = in.getInt();
153 while(count-- > 0) {
154 int typeCode = in.get();
155 if(typeCode == DataEnum.EOD.code) {
156 return JobStatus.FINISHED;
157 }
158
159 BookReader reader = map.get(typeCode);
160 if(reader == null) {
161 throw new ProtocolException("unrecognized type: " + typeCode, in);
162 }
163
164 reader.read(header, in);
165 }
166
167 return JobStatus.ACTIVE;
168 }
169
170 @Override
171 public final CommandEnum getCancelCommand() {
172 return CommandEnum.CANCEL_HIST_DATA; // fixme??
173 }
174 }