001package jmri.util.com.rbnb;
002
003// This class comes from the Java2s code examples at
004// http://www.java2s.com/Code/Java/Network-Protocol/UDPOutputStream.htm
005/*
006
007 Copyright 2007 Creare Inc.
008
009 Licensed under the Apache License, Version 2.0 (the "License"); 
010 you may not use this file except in compliance with the License. 
011 You may obtain a copy of the License at 
012
013 http://www.apache.org/licenses/LICENSE-2.0 
014
015 Unless required by applicable law or agreed to in writing, software 
016 distributed under the License is distributed on an "AS IS" BASIS, 
017 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
018 See the License for the specific language governing permissions and 
019 limitations under the License.
020 */
021
022/*
023 *****************************************************************
024 ***                ***
025 ***  Name :  UDPOutputStream                                 ***
026 ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
027 ***  For  :  E-Scan            ***
028 ***  Date :  October, 2001          ***
029 ***                ***
030 ***  Copyright 2001 Creare Inc.        ***
031 ***  All Rights Reserved          ***
032 ***                ***
033 ***  Description :            ***
034 ***       This class extends OutputStream, providing its API  ***
035 ***   for calls to a UDPSocket.                               ***
036 ***                ***
037 ***   NB: THIS CLASS IS NOT THREADSAFE.  DO NOT SHARE ONE    ***
038 ***      INSTANCE OF THIS CLASS AMONG MULTIPLE THREADS.       ***
039 ***                ***
040 *****************************************************************
041 */
042
043import java.io.IOException;
044import java.io.OutputStream;
045import java.net.DatagramPacket;
046import java.net.DatagramSocket;
047import java.net.InetAddress;
048import java.net.SocketException;
049import java.net.UnknownHostException;
050
051public class UDPOutputStream extends OutputStream {
052
053    public static final int DEFAULT_BUFFER_SIZE = 1024;
054    public static final int DEFAULT_MAX_BUFFER_SIZE = 8192;
055
056    protected DatagramSocket dsock = null;
057    DatagramPacket dpack = null;
058    InetAddress iAdd = null;
059    int port = 0;
060
061    byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
062    byte[] outdata = null;
063    int idx = 0; // buffer index; points to next empty buffer byte
064    int bufferMax = DEFAULT_MAX_BUFFER_SIZE;
065
066    /*
067     * ******************** constructors *******************
068     */
069    /*
070     *****************************************************************
071     ***                ***
072     ***  Name :  UDPOutputStream                                 ***
073     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
074     ***  For  :  E-Scan            ***
075     ***  Date :  October, 2001          ***
076     ***                ***
077     ***  Copyright 2001 Creare Inc.        ***
078     ***  All Rights Reserved          ***
079     ***                ***
080     ***  Description :            ***
081     ***       Default constructor.                                ***
082     ***                ***
083     *****************************************************************
084     */
085    public UDPOutputStream() {
086    }
087
088    /*
089     *****************************************************************
090     ***                ***
091     ***  Name :  UDPOutputStream                                 ***
092     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
093     ***  For  :  E-Scan            ***
094     ***  Date :  October, 2001          ***
095     ***                ***
096     ***  Copyright 2001 Creare Inc.        ***
097     ***  All Rights Reserved          ***
098     ***                ***
099     ***  Description :            ***
100     ***       Constructor.  Sets size of buffer.                  ***
101     ***                ***
102     *****************************************************************
103     */
104    public UDPOutputStream(int buffSize) {
105        setBufferSize(buffSize);
106    }
107
108    /*
109     *****************************************************************
110     ***                ***
111     ***  Name :  UDPOutputStream                                 ***
112     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
113     ***  For  :  E-Scan            ***
114     ***  Date :  October, 2001          ***
115     ***                ***
116     ***  Copyright 2001 Creare Inc.        ***
117     ***  All Rights Reserved          ***
118     ***                ***
119     ***  Description :            ***
120     ***       Constructor.  Sets the address and port of the  UDP ***
121     ***   socket to write to.                                     ***
122     ***                ***
123     *****************************************************************
124     */
125    public UDPOutputStream(String address, int portI)
126            throws UnknownHostException, SocketException, IOException {
127
128        open(InetAddress.getByName(address), portI);
129    }
130
131    /*
132     *****************************************************************
133     ***                ***
134     ***  Name :  UDPOutputStream                                 ***
135     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
136     ***  For  :  E-Scan            ***
137     ***  Date :  November, 2001          ***
138     ***                ***
139     ***  Copyright 2001 Creare Inc.        ***
140     ***  All Rights Reserved          ***
141     ***                ***
142     ***  Description :            ***
143     ***       Constructor.  Sets the address and port of the  UDP ***
144     ***   socket to write to.                                     ***
145     ***                ***
146     *****************************************************************
147     */
148    public UDPOutputStream(InetAddress address, int portI)
149            throws SocketException, IOException {
150
151        open(address, portI);
152    }
153
154    /*
155     *****************************************************************
156     ***                ***
157     ***  Name :  UDPOutputStream                                 ***
158     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
159     ***  For  :  E-Scan            ***
160     ***  Date :  October, 2001          ***
161     ***                ***
162     ***  Copyright 2001 Creare Inc.        ***
163     ***  All Rights Reserved          ***
164     ***                ***
165     ***  Description :            ***
166     ***       Constructor.  Sets the address and port of the  UDP ***
167     ***   socket to write to.  Sets the size of the buffer.       ***
168     ***                ***
169     *****************************************************************
170     */
171    public UDPOutputStream(String address, int portI, int buffSize)
172            throws UnknownHostException, SocketException, IOException {
173
174        open(InetAddress.getByName(address), portI);
175        setBufferSize(buffSize);
176    }
177
178    /*
179     *****************************************************************
180     ***                ***
181     ***  Name :  UDPOutputStream                                 ***
182     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
183     ***  For  :  E-Scan            ***
184     ***  Date :  October, 2001          ***
185     ***                ***
186     ***  Copyright 2001 Creare Inc.        ***
187     ***  All Rights Reserved          ***
188     ***                ***
189     ***  Description :            ***
190     ***       Constructor.  Sets the address and port of the  UDP ***
191     ***   socket to write to.  Sets the size of the buffer.       ***
192     ***                ***
193     *****************************************************************
194     */
195    public UDPOutputStream(InetAddress address, int portI, int buffSize)
196            throws SocketException, IOException {
197
198        open(address, portI);
199        setBufferSize(buffSize);
200    }
201
202    /*
203     * ********** opening and closing the stream ***********
204     */
205    /*
206     *****************************************************************
207     ***                ***
208     ***  Name :  open                                             ***
209     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
210     ***  For  :  E-Scan            ***
211     ***  Date :  October, 2001          ***
212     ***                ***
213     ***  Copyright 2001 Creare Inc.        ***
214     ***  All Rights Reserved          ***
215     ***                ***
216     ***  Description :            ***
217     ***       The user may use this method to set the address and ***
218     ***   port of the UDP socket to write to.                     ***
219     ***                ***
220     *****************************************************************
221     */
222    public void open(InetAddress address, int portI)
223            throws SocketException, IOException {
224
225        dsock = new DatagramSocket();
226        iAdd = address;
227        port = portI;
228    }
229
230    /*
231     *****************************************************************
232     ***                ***
233     ***  Name :  close                                       ***
234     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
235     ***  For  :  E-Scan            ***
236     ***  Date :  October, 2001          ***
237     ***                ***
238     ***  Copyright 2001 Creare Inc.        ***
239     ***  All Rights Reserved          ***
240     ***                ***
241     ***  Description :            ***
242     ***       Close the UDP socket and UDPOutputStream.           ***
243     ***                ***
244     *****************************************************************
245     */
246    @Override
247    public void close() throws IOException {
248        dsock.close();
249        dsock = null;
250        idx = 0;
251    }
252
253    /*
254     * ********* writing to and flushing the buffer ***********
255     */
256    /*
257     *****************************************************************
258     ***                ***
259     ***  Name :  flush                                     ***
260     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
261     ***  For  :  E-Scan            ***
262     ***  Date :  October, 2001          ***
263     ***                ***
264     ***  Copyright 2001 Creare Inc.        ***
265     ***  All Rights Reserved          ***
266     ***                ***
267     ***  Description :            ***
268     ***       Flush current buffer contents to UDP socket.        ***
269     ***                ***
270     *****************************************************************
271     */
272    @Override
273    public void flush() throws IOException {
274        if (idx == 0) {  // no data in buffer
275            return;
276        }
277
278        // copy what we have in the buffer so far into a new array;
279        // if buffer is full, use it directly.
280        if (idx == buffer.length) {
281            outdata = buffer;
282        } else {
283            outdata = new byte[idx];
284            System.arraycopy(buffer,
285                    0,
286                    outdata,
287                    0,
288                    idx);
289        }
290
291        // send data
292        dpack = new DatagramPacket(outdata, idx, iAdd, port);
293        dsock.send(dpack);
294
295        // reset buffer index
296        idx = 0;
297    }
298
299    /*
300     *****************************************************************
301     ***                ***
302     ***  Name :  write(int)                                     ***
303     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
304     ***  For  :  E-Scan            ***
305     ***  Date :  October, 2001          ***
306     ***                ***
307     ***  Copyright 2001 Creare Inc.        ***
308     ***  All Rights Reserved          ***
309     ***                ***
310     ***  Description :            ***
311     ***       Writes the input value to the UDP socket.  May      ***
312     ***   buffer the value.                                       ***
313     ***       Input value is converted to a byte.                 ***
314     ***                ***
315     *****************************************************************
316     */
317    @Override
318    public void write(int value) throws IOException {
319        buffer[idx] = (byte) (value & 0x0ff);
320        idx++;
321
322        if (idx >= buffer.length) {
323            flush();
324        }
325    }
326
327    /*
328     *****************************************************************
329     ***                ***
330     ***  Name :  write(byte[])                                 ***
331     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
332     ***  For  :  E-Scan            ***
333     ***  Date :  October, 2001          ***
334     ***                ***
335     ***  Copyright 2001 Creare Inc.        ***
336     ***  All Rights Reserved          ***
337     ***                ***
338     ***  Description :            ***
339     ***       Writes the input byte array to the UDP socket.  May ***
340     ***   buffer the values.                                      ***
341     ***                ***
342     *****************************************************************
343     */
344    @Override
345    public void write(byte[] data) throws IOException {
346        write(data, 0, data.length);
347    }
348
349    /*
350     *****************************************************************
351     ***                ***
352     ***  Name :  write(byte[], int, int)                         ***
353     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
354     ***  For  :  E-Scan            ***
355     ***  Date :  October, 2001          ***
356     ***                ***
357     ***  Copyright 2001 Creare Inc.        ***
358     ***  All Rights Reserved          ***
359     ***                ***
360     ***  Description :            ***
361     ***       Writes len bytes of the input byte array to the UDP ***
362     ***   socket, starting at offset off.  May buffer the values. ***
363     ***                ***
364     *****************************************************************
365     */
366    @Override
367    public void write(byte[] data, int off, int len) throws IOException {
368        int lenRemaining = len;
369
370        try {
371            while (buffer.length - idx <= lenRemaining) {
372                System.arraycopy(data,
373                        off + (len - lenRemaining),
374                        buffer,
375                        idx,
376                        buffer.length - idx);
377                lenRemaining -= buffer.length - idx;
378                idx = buffer.length;
379                flush();
380            }
381
382            if (lenRemaining == 0) {
383                return;
384            }
385
386            System.arraycopy(data,
387                    off + (len - lenRemaining),
388                    buffer,
389                    idx,
390                    lenRemaining);
391            idx += lenRemaining;
392        } catch (ArrayIndexOutOfBoundsException e) {
393            // 04/03/02 UCB - DEBUG
394            System.err.println("len: " + len);
395            System.err.println("lenRemaining: " + lenRemaining);
396            System.err.println("idx: " + idx);
397            System.err.println("buffer.length: " + buffer.length);
398            System.err.println("offset: " + off);
399            System.err.println("data.length: " + data.length);
400            throw e;
401        }
402    }
403
404    /*
405     * ***************** buffer size accesors *****************
406     */
407    /*
408     *****************************************************************
409     ***                ***
410     ***  Name :  getBufferSize                                 ***
411     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
412     ***  For  :  E-Scan            ***
413     ***  Date :  October, 2001          ***
414     ***                ***
415     ***  Copyright 2001 Creare Inc.        ***
416     ***  All Rights Reserved          ***
417     ***                ***
418     ***  Description :            ***
419     ***       How many bytes are buffered before being flushed.   ***
420     ***                ***
421     *****************************************************************
422     */
423    public int getBufferSize() {
424        return buffer.length;
425    }
426
427    /*
428     *****************************************************************
429     ***                ***
430     ***  Name :  setMaxBufferSize()                        ***
431     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
432     ***  For  :  E-Scan            ***
433     ***  Date :  November, 2001          ***
434     ***                ***
435     ***  Copyright 2001 Creare Inc.        ***
436     ***  All Rights Reserved          ***
437     ***                ***
438     ***  Description :            ***
439     ***       Allows user to set upper limit on output buffer     ***
440     ***   size.  Set by default to DEFAULT_MAX_BUFFER_SIZE.       ***
441     ***                ***
442     *****************************************************************
443     */
444    public void setMaxBufferSize(int max) {
445        bufferMax = max;
446    }
447
448    /*
449     *****************************************************************
450     ***                ***
451     ***  Name :  setBufferSize()                                ***
452     ***  By   :  U. Bergstrom   (Creare Inc., Hanover, NH)  ***
453     ***  For  :  E-Scan            ***
454     ***  Date :  October, 2001          ***
455     ***                ***
456     ***  Copyright 2001 Creare Inc.        ***
457     ***  All Rights Reserved          ***
458     ***                ***
459     ***  Description :            ***
460     ***       Sets the length of the buffer.  Must be at least 1  ***
461     ***   byte long.  Tries to flush any data currently in buffer ***
462     ***   before resetting the size.                              ***
463     ***                ***
464     *****************************************************************
465     */
466    public void setBufferSize(int buffSize) {
467        try {
468            flush();
469        } catch (IOException ioe) {
470        }
471
472        if (buffSize == buffer.length) {
473            // a no-op; we are already the right size
474            return;
475        } else if (buffSize > 0) {
476            if (buffSize > bufferMax) {
477                buffer = new byte[bufferMax];
478            } else {
479                buffer = new byte[buffSize];
480            }
481        } else {
482            buffer = new byte[1];
483        }
484    }
485}