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    }