PageRenderTime 26ms CodeModel.GetById 10ms app.highlight 12ms RepoModel.GetById 2ms app.codeStats 0ms

/protocols/smpp/src/main/java/org/mobicents/protocols/smpp/net/ReplayLink.java

http://mobicents.googlecode.com/
Java | 219 lines | 161 code | 24 blank | 34 comment | 19 complexity | 96534905614e456fece0c0aa86b4dd96 MD5 | raw file
  1/*
  2 * JBoss, Home of Professional Open Source
  3 * Copyright 2011, Red Hat, Inc. and individual contributors
  4 * by the @authors tag. See the copyright.txt in the distribution for a
  5 * full listing of individual contributors.
  6 *
  7 * This is free software; you can redistribute it and/or modify it
  8 * under the terms of the GNU Lesser General Public License as
  9 * published by the Free Software Foundation; either version 2.1 of
 10 * the License, or (at your option) any later version.
 11 *
 12 * This software is distributed in the hope that it will be useful,
 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 15 * Lesser General Public License for more details.
 16 *
 17 * You should have received a copy of the GNU Lesser General Public
 18 * License along with this software; if not, write to the Free
 19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 21 */
 22
 23package org.mobicents.protocols.smpp.net;
 24
 25import java.io.EOFException;
 26import java.io.IOException;
 27import java.io.InputStream;
 28import java.util.ArrayList;
 29import java.util.HashSet;
 30import java.util.List;
 31import java.util.Set;
 32
 33import org.mobicents.protocols.smpp.message.SMPPPacket;
 34import org.mobicents.protocols.smpp.util.PacketDecoderImpl;
 35import org.mobicents.protocols.smpp.util.PacketFactory;
 36import org.mobicents.protocols.smpp.util.SMPPIO;
 37
 38/**
 39 * An implementation of the SmscLink interface which can be used to replay
 40 * an SMPP session.
 41 * <p>
 42 * This implementation is intended to be used in conjunction with data
 43 * captured from a real SMPP session. All outbound bytes should be captured
 44 * in one location and all inbound bytes in another. This link will
 45 * reconstitute the SMPP packets for the session and provide response
 46 * packets only after it has seen the request packets being sent.
 47 * </p>
 48 * @version $Id: ReplayLink.java 457 2009-01-15 17:37:42Z orank $
 49 *
 50 */
 51public class ReplayLink implements SmscLink {
 52
 53    private InputStream inPacketSource;
 54    private InputStream outPacketSource;
 55    private int timeout = 0;
 56    private boolean connected;
 57    private PacketFactory packetFactory = new PacketFactory();
 58    private Set<Long> outboundSeqNums = new HashSet<Long>();
 59    private List<SMPPPacket> packetLookahead = new ArrayList<SMPPPacket>();
 60    private byte[] header = new byte[16];
 61    private byte[] packet = new byte[512];
 62    private TestDecoder decoder = new TestDecoder();
 63    
 64    public ReplayLink(InputStream inPacketSource, InputStream outPacketSource) {
 65        this.inPacketSource = inPacketSource;
 66        this.outPacketSource = outPacketSource;
 67    }
 68    
 69    public void connect() throws IOException {
 70        connected = true;
 71        lookahead(10);
 72    }
 73
 74    public void disconnect() throws IOException {
 75        connected = false;
 76        packetLookahead.clear();
 77    }
 78
 79    public void flush() throws IOException {
 80    }
 81
 82    public int getTimeout() {
 83        return timeout;
 84    }
 85    
 86    public void setTimeout(int timeout) {
 87        this.timeout = timeout;
 88    }
 89
 90    public boolean isConnected() {
 91        return connected;
 92    }
 93
 94    public boolean isTimeoutSupported() {
 95        return false;
 96    }
 97
 98    public SMPPPacket getNextOutbound() throws IOException {
 99        synchronized (decoder) {
100            return readOnePacket(outPacketSource);
101        }
102    }
103    
104    public SMPPPacket read() throws IOException {
105        if (!connected) {
106            throw new IllegalStateException("Not connected.");
107        }
108        if (packetLookahead.size() < 3) {
109            lookahead(50);
110        }
111        if (packetLookahead.size() == 0) {
112            throw new EOFException();
113        }
114        SMPPPacket entry = packetLookahead.get(0);
115        Long sequence = new Long(entry.getSequenceNum());
116        if (entry.isResponse() && !outboundSeqNums.contains(sequence)) {
117            blockUntilRequestSent(sequence);
118        }
119        return packetLookahead.remove(0);
120    }
121
122    public void write(SMPPPacket packet, boolean withOptionalParams)
123            throws IOException {
124        if (!connected) {
125            throw new IllegalStateException("Not connected.");
126        }
127        Long seq = new Long(packet.getSequenceNum());
128        synchronized (this) {
129            outboundSeqNums.add(seq);
130            notifyAll();
131        }
132    }
133
134    private void lookahead(int number) throws IOException {
135        synchronized (decoder) {
136            for (int i = 0; i < number; i++) {
137                SMPPPacket packet = readOnePacket(inPacketSource);
138                if (packet == null) {
139                    break;
140                }
141                packetLookahead.add(packet);
142            }
143        }
144    }
145
146    private void blockUntilRequestSent(Long sequence) {
147        try {
148            synchronized (this) {
149                if (!outboundSeqNums.contains(sequence)) {
150                    wait(timeout);
151                }
152                if (!outboundSeqNums.contains(sequence)) {
153                    throw new ReadTimeoutException();
154                }
155            }
156        } catch (InterruptedException x) {
157        }
158    }
159    
160    private SMPPPacket readOnePacket(InputStream source) throws IOException {
161        int count = 0;
162        while (count < 16) {
163            int n = source.read(header, 0, 16 - count);
164            if (n < 0) {
165                return null;
166            }
167            count += n;
168        }
169        int length = SMPPIO.readInt4(header, 0);
170        if (length > packet.length) {
171            packet = new byte[length];
172        }
173        while (count < length) {
174            int n = source.read(packet, count - 16, length - count);
175            if (n < 0) {
176                return null;
177            }
178            count += n;
179        }
180        int id = SMPPIO.readInt4(header, 4);
181        SMPPPacket packet = packetFactory.newInstance(id);
182        decoder.reset(count);
183        packet.readFrom(decoder);
184        return packet;
185    }
186    
187    private class TestDecoder extends PacketDecoderImpl {
188        int offset;
189        int available;
190        
191        public void reset(int byteCount) {
192            setBytes(header);
193            setParsePosition(0);
194            offset = 0;
195            available = byteCount;
196        }
197        
198        @Override
199        public int getAvailableBytes() {
200            return available;
201        }
202        
203        @Override
204        public long readUInt4() {
205            long val = super.readUInt4();
206            if (getParsePosition() == 16) {
207                setBytes(packet);
208                setParsePosition(0);
209                offset = 16;
210            }
211            return val;
212        }
213        
214        @Override
215        public int getParsePosition() {
216            return offset + super.getParsePosition();
217        }
218    }
219}