/[webpac]/trunk2/openisis/org/openisis/PlainSerializer.java
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk2/openisis/org/openisis/PlainSerializer.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 337 - (show annotations)
Thu Jun 10 19:22:40 2004 UTC (19 years, 10 months ago) by dpavlin
File size: 13278 byte(s)
new trunk for webpac v2

1 /*
2 openisis - an open implementation of the CDS/ISIS database
3 Version 0.8.x (patchlevel see file Version)
4 Copyright (C) 2001-2003 by Erik Grziwotz, erik@openisis.org
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 see README for more information
21 EOH */
22
23 package org.openisis;
24
25 import java.io.*;
26 import java.net.Socket;
27 import java.util.ArrayList;
28
29 /**
30 Serialization of fields by plain protocol.
31 <p>
32 $Id: PlainSerializer.java,v 1.8 2003/05/02 18:41:55 mawag Exp $
33 @version $Revision: 1.8 $
34 @author $Author: mawag $
35 */
36 public class PlainSerializer {
37
38 private static class ProtocolViolation extends RuntimeException {
39 ProtocolViolation () {
40 super ();
41 }
42 ProtocolViolation (String msg) {
43 super (msg);
44 }
45 ProtocolViolation (byte arr[]) {
46 super ("got <" + new String (arr) + ">");
47 }
48 }
49
50 private static class ByteBuf {
51 byte _b[];
52 int _cap, _pos;
53 ByteBuf (int cap) {
54 _b = new byte [_cap = cap];
55 _pos = 0;
56 }
57 void append (byte b[], int off, int len) {
58 if (0 < len) {
59 int np = _pos + len;
60 if (np > _cap) {
61 int nc = _cap;
62 while (np > (nc *= 2)) {
63 ;
64 }
65 byte nb[] = new byte [nc];
66 System.arraycopy (_b, 0, nb, 0, _pos);
67 _b = nb;
68 _cap = nc;
69 }
70 System.arraycopy (b, off, _b, _pos, len);
71 _pos = np;
72 }
73 }
74 }
75
76 private static final byte[] NL = new byte [] { (byte)'\n' };
77 private static final byte[] HT = new byte [] { (byte)'\t' };
78 private static final byte[] VT = new byte [] { (byte)11 };
79
80 private InputStream _in;
81 private OutputStream _out;
82 private String _enc = null;
83 private boolean _dbg = false;
84 private boolean _bin = false;
85
86 private final void _write (byte[] arr, int off, int len) throws Exception {
87 if (_dbg) {
88 Log.verbose (this,
89 "w <" + new String (arr, off, len) + ">", null);
90 }
91 _out.write (arr, off, len);
92 }
93
94 private final void _write (byte[] arr) throws Exception {
95 if (_dbg) {
96 Log.verbose (this,
97 "w <" + new String (arr, 0, arr.length) + ">", null);
98 }
99 _out.write (arr);
100 }
101
102 private final int _read (byte[] arr) throws Exception {
103 int rd = _in.read (arr);
104 if (_dbg) {
105 Log.verbose (this,
106 "r <" + new String (arr, 0, rd) + ">", null);
107 }
108 return rd;
109 }
110
111 /** write end of record to output stream.
112 @return success
113 */
114 public boolean flush () {
115 try {
116 _write (NL);
117 return true;
118 }
119 catch (Exception ex) {
120 Log.warn (this, "flush", ex);
121 }
122 return false;
123 }
124
125 /** serialize one field.
126 @return success
127 */
128 public boolean write (Field fld) {
129 int j, lst;
130 byte[] bv;
131
132 if (null == fld) {
133 return false;
134 }
135 try {
136 bv = Integer.toString (fld.tag).getBytes ();
137 _write (bv);
138 _write (HT);
139 if (null != fld.val && 0 < fld.val.length ()) {
140 bv = null != _enc ?
141 fld.val.getBytes (_enc) : fld.val.getBytes ();
142 lst = j = 0;
143 while (bv.length > j) {
144 if (NL[0] != bv[j]) {
145 ++j;
146 continue;
147 }
148 if (_bin) {
149 ++j;
150 _write (bv, lst, j - lst);
151 _write (HT);
152 }
153 else {
154 if (j > lst) {
155 _write (bv, lst, j - lst);
156 }
157 _write (VT);
158 ++j;
159 }
160 lst = j;
161 }
162 if (bv.length > lst) {
163 _write (bv, lst, bv.length - lst);
164 }
165 }
166 _write (NL);
167 return true;
168 }
169 catch (Exception ex) {
170 Log.warn (this, "serializing " + fld, ex);
171 }
172 return false;
173 }
174
175 /** serialize fields.
176 @return success
177 */
178 public boolean write (Field[] flds) {
179 if (null == flds) {
180 return false;
181 }
182 for (int j = 0; flds.length > j; ++j) {
183 if (! write (flds[j])) {
184 return false;
185 }
186 }
187 return flush ();
188 }
189
190 /** deserialize fields.
191 @return array of fields read from input stream, null on error
192 */
193 public Field[] read () {
194 byte[] rbuf = new byte [1024];
195 ByteBuf sbuf = new ByteBuf (1024);
196 ArrayList lst = new ArrayList ();
197 Field fld;
198 int rd, pos, tag, vs, val;
199 boolean rdt; // reading tag
200 boolean lnl; // last byte was NL
201 boolean neg; // tag negative
202 boolean bin = _bin;
203
204 try {
205 tag = 0;
206 rdt = true;
207 neg = false;
208 lnl = false;
209 all:
210 while (true) {
211 rd = _read (rbuf);
212 if (0 >= rd) {
213 throw new ProtocolViolation ("no more bytes available");
214 }
215 vs = pos = 0;
216 while (pos < rd) {
217 if (rdt) {
218 if (HT[0] == rbuf[pos]) {
219 rdt = false;
220 vs = ++pos;
221 continue;
222 }
223 if (0 == tag && '-' == rbuf[pos]) {
224 neg = true;
225 ++pos;
226 continue;
227 }
228 val = rbuf[pos] - '0';
229 if (0 > val || 9 < val) {
230 if (0 == pos &&
231 NL[0] == rbuf[0] &&
232 0 == lst.size ()) {
233 Log.warn (this, null,
234 new ProtocolViolation ("empty response"));
235 break;
236 }
237 throw new ProtocolViolation (rbuf);
238 }
239 tag = 10 * tag + val;
240 ++pos;
241 continue;
242 }
243 if (lnl) {
244 lnl = false;
245 if (HT[0] == rbuf[pos]) {
246 bin = true;
247 sbuf.append (NL, 0, 1);
248 vs = ++pos;
249 continue;
250 }
251 fld = new Field (neg ? - tag : tag,
252 null == _enc ?
253 new String (sbuf._b, 0, sbuf._pos) :
254 new String (sbuf._b, 0, sbuf._pos, _enc)
255 );
256 lst.add (fld);
257 if (NL[0] == rbuf[pos]) {
258 if (pos != rd - 1) {
259 throw new ProtocolViolation ("trailing bytes");
260 }
261 break all;
262 }
263 sbuf._pos = 0;
264 rdt = true;
265 neg = false;
266 tag = 0;
267 continue;
268 }
269 if (VT[0] == rbuf[pos]) {
270 if (! bin) {
271 rbuf[pos] = NL[0];
272 }
273 }
274 else if (NL[0] == rbuf[pos]) {
275 if (pos > vs) {
276 sbuf.append (rbuf, vs, pos - vs);
277 }
278 lnl = true;
279 }
280 ++pos;
281 }
282 if (! rdt && rd > vs) {
283 sbuf.append (rbuf, vs, rd - vs);
284 }
285 }
286
287 return (Field[]) lst.toArray (new Field [lst.size ()]);
288 }
289 catch (Exception ex) {
290 Log.warn (this, "read", ex);
291 }
292 return null;
293 }
294
295 public void setBinaryMode (boolean bin) {
296 _bin = bin;
297 }
298
299 /** Set character encoding to use in subsequent calls to
300 read and write.
301 @param enc if null, the platforms default encoding will be used
302 */
303 public void setEncoding (String enc) {
304 if (null != enc) {
305 try {
306 new String (NL, enc);
307 }
308 catch (UnsupportedEncodingException ex) {
309 Log.warn (this, "setEncoding(" + enc + ")", ex);
310 return;
311 }
312 }
313 _enc = enc;
314 }
315
316 /** Constructor with read and write stream.
317 @param enc character encoding
318 @param bin binary mode
319 */
320 public PlainSerializer (
321 InputStream in, OutputStream out, String enc, boolean bin
322 ) {
323 _in = in;
324 _out = out;
325 setEncoding (enc);
326 setBinaryMode (bin);
327 Log.info (this, "ctor(" + enc + "," + bin + ")", null);
328 }
329
330 /** Constructor using text mode and platforms default encoding.
331 */
332 public PlainSerializer (InputStream in, OutputStream out) {
333 this (in, out, null, false);
334 }
335
336 /** Constructor for a socket connection to port@host.
337 @param enc character encoding
338 @param bin binary mode
339 @exception all exceptions a socket might throw
340 */
341 public PlainSerializer (
342 String hostname, int port, String enc, boolean bin
343 ) throws Exception {
344 try {
345 Socket sock = new Socket (hostname, port);
346 _in = sock.getInputStream ();
347 _out = sock.getOutputStream ();
348 setEncoding (enc);
349 setBinaryMode (bin);
350 Log.info (this, "ctor(" + hostname + ',' + port + "," +
351 enc + "," + bin + ")", null);
352 }
353 catch (Exception ex) {
354 Log.warn (this, "ctor(" + hostname + ',' + port + ")", ex);
355 throw ex;
356 }
357 }
358
359 /** Constructor using text mode and platforms default encoding.
360 */
361 public PlainSerializer (String hostname, int port) throws Exception {
362 this (hostname, port, null, false);
363 }
364
365 /** Close communication channels.
366 */
367 public void close () {
368 if (null != _in) {
369 try {
370 _in.close ();
371 }
372 catch (Exception ex) {
373 }
374 _in = null;
375 }
376 if (null != _out) {
377 try {
378 _out.close ();
379 }
380 catch (Exception ex) {
381 }
382 _out = null;
383 }
384 }
385
386 // //////////////////////////////////////////////////////////////////////
387
388 private class PSWriter extends Thread {
389 Field[] _rqs;
390 int _numr;
391 PSWriter (Field[] rqs, int numr) {
392 _rqs = rqs;
393 _numr = numr;
394 }
395 public void run () {
396 for (int j = 0; _numr > j; ++j) {
397 if (! write (_rqs)) {
398 Log.warn (null, "error writing rqs #" + j, null);
399 System.exit (1);
400 }
401 try {
402 synchronized (PSWriter.this) {
403 PSWriter.this.wait ();
404 }
405 }
406 catch (Exception ex) {
407 Log.warn (PSWriter.this, "wait", ex);
408 }
409 }
410 }
411 }
412
413 /** Tester:<br/><pre>
414 java org.openisis.PlainSerializer -p
415 java org.openisis.PlainSerializer -b -p
416 java org.openisis.PlainSerializer -e UTF-8 -p
417 java org.openisis.PlainSerializer -e UTF-8 -b -p
418 java org.openisis.PlainSerializer -e UTF-16 -p
419 java org.openisis.PlainSerializer -e UTF-16 -b -p
420 java org.openisis.PlainSerializer -p 55
421 java org.openisis.PlainSerializer -b -p 55
422 java org.openisis.PlainSerializer -e UTF-16 -p 55
423 java org.openisis.PlainSerializer -e UTF-16 -b -p 55
424 </pre>
425 */
426 public static void main (String argv[]) {
427 try {
428 String novel = "blah";
429 String host = "localhost";
430 String enc = null;
431 int port = 8080;
432 int numr = 1;
433 boolean pipe = false;
434 boolean dbg = false;
435 boolean bin = false;
436 int j = 0;
437 int len = argv.length;
438
439 for (int jj = 0; argv.length > jj; ++jj) {
440 if (argv[jj].startsWith ("-d")) {
441 dbg = true;
442 ++j;
443 --len;
444 continue;
445 }
446 if (argv[jj].startsWith ("-b")) {
447 bin = true;
448 ++j;
449 --len;
450 continue;
451 }
452 if (argv[jj].startsWith ("-e")) {
453 enc = argv[++jj];
454 j += 2;
455 len -= 2;
456 continue;
457 }
458 break;
459 }
460 switch (len) {
461 case 3:
462 numr = Integer.parseInt (argv[2 + j]);
463 case 2:
464 if (argv[j].startsWith ("-p")) {
465 pipe = true;
466 numr = Integer.parseInt (argv[1 + j]);
467 break;
468 }
469 port = Integer.parseInt (argv[1 + j]);
470 case 1:
471 if (argv[j].startsWith ("-p")) {
472 pipe = true;
473 }
474 else {
475 host = argv[j];
476 }
477 case 0:
478 break;
479 default:
480 throw new IllegalArgumentException ();
481 }
482
483 PlainSerializer ps;
484 if (pipe) {
485 PipedInputStream pi = new PipedInputStream ();
486 PipedOutputStream po = new PipedOutputStream (pi);
487 ps = new PlainSerializer (pi, po, enc, bin);
488 }
489 else {
490 ps = new PlainSerializer (host, port, enc, bin);
491 }
492 ps._dbg = dbg;
493 for (j = 0; 8 > j; ++j) {
494 novel = novel + novel;
495 }
496 String[] vals = new String [] {
497 "localhorst",
498 "nothing",
499 "one",
500 null,
501 "",
502 novel,
503 "\nfive\nfire\t",
504 "\t\n\t\n" + (bin ? new String (VT) : ""),
505 "seven",
506 "\n"
507 };
508 Field[] rqs = new Field [] {
509 new Field (-2, vals[0]),
510 new Field (0, vals[1]),
511 new Field (1, vals[2]),
512 new Field (2, vals[3]),
513 new Field (3, vals[4]),
514 new Field (4, vals[5]),
515 new Field (5, vals[6]),
516 new Field (6, vals[7]),
517 new Field (7, vals[8]),
518 new Field (8, vals[9])
519 };
520 int k, kk;
521 Field[] rsp;
522 PSWriter writer = ps.new PSWriter (rqs, numr);
523 writer.start ();
524
525 for (j = 0; numr > j; ++j) {
526 rsp = ps.read ();
527 if (null == rsp) {
528 Log.warn (null, "error reading rsp #" + j, null);
529 System.exit (1);
530 }
531 for (k = kk = 0; rsp.length > k; ++k) {
532 if (0 > rsp[k].tag) {
533 if (kk >= rqs.length || ! rsp[k].equals (rqs[kk])) {
534 // skip additional server fields
535 if (dbg) {
536 Log.verbose (null, "skipping server field " +
537 rsp[k] + " ...", null);
538 }
539 continue;
540 }
541 }
542 if (rqs.length <= kk) {
543 for (kk = 0; rsp.length > kk; ++kk) {
544 Log.verbose (new Integer (kk),
545 rsp[kk].toString (), null);
546 }
547 Log.warn (null,
548 "length mismatch rsp #" + j + ": " + k + "/" +
549 kk + "/" + rsp.length + ">=" + rqs.length,
550 null);
551 System.exit (1);
552 }
553 if (! rsp[k].equals (rqs[kk])) {
554 Log.warn (null, "field #" + k + " rqs #" + j +
555 " differs: <" + rsp[k] + "> != <" + rqs[kk] +
556 ">", null);
557 System.exit (1);
558 }
559 ++kk;
560 }
561 if (0 != j && 0 == (j % 100)) {
562 System.out.println (j + " ...");
563 }
564 synchronized (writer) {
565 writer.notify ();
566 }
567 }
568 ps.close ();
569
570 System.out.println ("ok.");
571 }
572 catch (Exception ex) {
573 ex.printStackTrace (System.err);
574 System.err.println ("usage: " + PlainSerializer.class.getName () +
575 " [-b(inary)] [-d(ebug)] [-e(ncoding) <name>]" +
576 " [<hostname=\"localhost\"> [<port> [<numrequests>]]] |" +
577 " -p(ipe) [<numrequests>]");
578 System.exit (1);
579 }
580 }
581 }
582

  ViewVC Help
Powered by ViewVC 1.1.26