1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.parser;
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.InternalErrorHandler;
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.stack.SIPStackTimerTask;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.*;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.*;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Input class for the pipelined parser. Buffer all bytes read from the socket
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and make them available to the message parser.
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan (Contains a bug fix contributed by Rob Daugherty (
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *         Lucent Technologies) )
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic class Pipeline extends InputStream {
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private LinkedList buffList;
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Buffer currentBuffer;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean isClosed;
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Timer timer;
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private InputStream pipe;
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private int readTimeout;
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private TimerTask myTimerTask;
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    class MyTimer extends SIPStackTimerTask {
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Pipeline pipeline;
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        private boolean isCancelled;
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        protected MyTimer(Pipeline pipeline) {
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.pipeline = pipeline;
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        protected void runTask() {
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.isCancelled)
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return;
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                pipeline.close();
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (IOException ex) {
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                InternalErrorHandler.handleException(ex);
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public boolean cancel() {
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean retval = super.cancel();
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.isCancelled = true;
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return retval;
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    class Buffer {
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        byte[] bytes;
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int length;
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int ptr;
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public Buffer(byte[] bytes, int length) {
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ptr = 0;
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.length = length;
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.bytes = bytes;
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public int getNextByte() {
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            int retval = bytes[ptr++] & 0xFF;
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return retval;
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void startTimer() {
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.readTimeout == -1)
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // TODO make this a tunable number. For now 4 seconds
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // between reads seems reasonable upper limit.
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.myTimerTask = new MyTimer(this);
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timer.schedule(this.myTimerTask, this.readTimeout);
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void stopTimer() {
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.readTimeout == -1)
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.myTimerTask != null)
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.myTimerTask.cancel();
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Pipeline(InputStream pipe, int readTimeout, Timer timer) {
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // pipe is the Socket stream
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // this is recorded here to implement a timeout.
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timer = timer;
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pipe = pipe;
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        buffList = new LinkedList();
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.readTimeout = readTimeout;
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void write(byte[] bytes, int start, int length) throws IOException {
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.isClosed)
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException("Closed!!");
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Buffer buff = new Buffer(bytes, length);
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        buff.ptr = start;
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.buffList) {
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buffList.add(buff);
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buffList.notifyAll();
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void write(byte[] bytes) throws IOException {
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.isClosed)
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IOException("Closed!!");
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Buffer buff = new Buffer(bytes, bytes.length);
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.buffList) {
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buffList.add(buff);
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            buffList.notifyAll();
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void close() throws IOException {
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.isClosed = true;
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.buffList) {
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.buffList.notifyAll();
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // JvB: added
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pipe.close();
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int read() throws IOException {
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // if (this.isClosed) return -1;
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.buffList) {
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (currentBuffer != null
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && currentBuffer.ptr < currentBuffer.length) {
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int retval = currentBuffer.getNextByte();
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentBuffer.ptr == currentBuffer.length)
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.currentBuffer = null;
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return retval;
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Bug fix contributed by Rob Daugherty.
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.isClosed && this.buffList.isEmpty())
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return -1;
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // wait till something is posted.
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (this.buffList.isEmpty()) {
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.buffList.wait();
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (this.isClosed)
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return -1;
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                currentBuffer = (Buffer) this.buffList.removeFirst();
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                int retval = currentBuffer.getNextByte();
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentBuffer.ptr == currentBuffer.length)
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.currentBuffer = null;
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return retval;
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (InterruptedException ex) {
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new IOException(ex.getMessage());
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (NoSuchElementException ex) {
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ex.printStackTrace();
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                throw new IOException(ex.getMessage());
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
197