Source for gnu.CORBA.IOR

   1: /* IOR.java --
   2:    Copyright (C) 2005 Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.CORBA;
  40: 
  41: import gnu.CORBA.CDR.BufferredCdrInput;
  42: import gnu.CORBA.CDR.BufferedCdrOutput;
  43: import gnu.CORBA.CDR.AbstractCdrInput;
  44: import gnu.CORBA.CDR.AbstractCdrOutput;
  45: import gnu.CORBA.GIOP.CharSets_OSF;
  46: import gnu.CORBA.GIOP.CodeSetServiceContext;
  47: 
  48: import org.omg.CORBA.BAD_PARAM;
  49: import org.omg.CORBA.CompletionStatus;
  50: import org.omg.CORBA.MARSHAL;
  51: import org.omg.CORBA.ULongSeqHelper;
  52: import org.omg.IOP.TAG_INTERNET_IOP;
  53: import org.omg.IOP.TAG_MULTIPLE_COMPONENTS;
  54: import org.omg.IOP.TaggedComponent;
  55: import org.omg.IOP.TaggedComponentHelper;
  56: import org.omg.IOP.TaggedProfile;
  57: import org.omg.IOP.TaggedProfileHelper;
  58: 
  59: import java.io.ByteArrayOutputStream;
  60: import java.io.IOException;
  61: import java.util.ArrayList;
  62: import java.util.Arrays;
  63: import java.util.zip.Adler32;
  64: 
  65: /**
  66:  * The implementaton of the Interoperable Object Reference (IOR). IOR can be
  67:  * compared with the Internet address for a web page, it provides means to
  68:  * locate the CORBA service on the web. IOR contains the host address, port
  69:  * number, the object identifier (key) inside the server, the communication
  70:  * protocol version, supported charsets and so on.
  71:  *
  72:  * Ths class provides method for encoding and decoding the IOR information
  73:  * from/to the stringified references, usually returned by
  74:  * {@link org.omg.CORBA.ORB#String object_to_string()}.
  75:  *
  76:  * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
  77:  *
  78:  * @see org.mog.CORBA.Object.object_to_string(Object forObject)
  79:  * @see string_to_object(String IOR)
  80:  */
  81: public class IOR
  82: {
  83:   /**
  84:    * The code sets tagged component, normally part of the Internet profile. This
  85:    * compone consists of the two componenets itself.
  86:    */
  87:   public static class CodeSets_profile
  88:   {
  89:     public CodeSets_profile()
  90:     {
  91:       int[] supported = CharSets_OSF.getSupportedCharSets();
  92: 
  93:       narrow.native_set = CharSets_OSF.NATIVE_CHARACTER;
  94:       narrow.conversion = supported;
  95: 
  96:       wide.native_set = CharSets_OSF.NATIVE_WIDE_CHARACTER;
  97:       wide.conversion = supported;
  98:     }
  99: 
 100:     /**
 101:      * The code set component.
 102:      */
 103:     public static class CodeSet_component
 104:     {
 105:       /**
 106:        * The conversion code sets.
 107:        */
 108:       public int[] conversion;
 109: 
 110:       /**
 111:        * The native code set.
 112:        */
 113:       public int native_set;
 114: 
 115:       /**
 116:        * Read from the CDR stream.
 117:        */
 118:       public void read(org.omg.CORBA.portable.InputStream in)
 119:       {
 120:         native_set = in.read_ulong();
 121:         conversion = ULongSeqHelper.read(in);
 122:       }
 123: 
 124:       /**
 125:        * Get a string representation.
 126:        */
 127:       public String toString()
 128:       {
 129:         StringBuffer b = new StringBuffer();
 130:         b.append("native " + name(native_set));
 131:         if (conversion != null && conversion.length > 0)
 132:           {
 133:             b.append(" conversion ");
 134:             for (int i = 0; i < conversion.length; i++)
 135:               {
 136:                 b.append(name(conversion[i]));
 137:                 b.append(' ');
 138:               }
 139:           }
 140:         b.append(' ');
 141:         return b.toString();
 142:       }
 143: 
 144:       /**
 145:        * Write into CDR stream.
 146:        */
 147:       public void write(org.omg.CORBA.portable.OutputStream out)
 148:       {
 149:         out.write_long(native_set);
 150:         ULongSeqHelper.write(out, conversion);
 151:       }
 152: 
 153:       private String name(int set)
 154:       {
 155:         return "0x" + Integer.toHexString(set) + " ("
 156:                + CharSets_OSF.getName(set) + ") ";
 157:       }
 158:     }
 159: 
 160:     /**
 161:      * The agreed tag for the Codesets profile.
 162:      */
 163:     public static final int TAG_CODE_SETS = 1;
 164: 
 165:     /**
 166:      * Information about narrow character encoding (TCS-C).
 167:      */
 168:     public CodeSet_component narrow = new CodeSet_component();
 169: 
 170:     /**
 171:      * About wide character encoding (TCS-W).
 172:      */
 173:     public CodeSet_component wide = new CodeSet_component();
 174: 
 175:     /**
 176:      * The negotiated coding result for this IOR. Saves time, requred for
 177:      * negotiation computations.
 178:      */
 179:     public CodeSetServiceContext negotiated;
 180: 
 181:     /**
 182:      * Read the code set profile information from the given input stream.
 183:      *
 184:      * @param profile a stream to read from.
 185:      */
 186:     public void read(AbstractCdrInput profile)
 187:     {
 188:       BufferredCdrInput encapsulation = profile.read_encapsulation();
 189:       narrow.read(encapsulation);
 190:       wide.read(encapsulation);
 191:     }
 192: 
 193:     /**
 194:      * Returns a string representation.
 195:      */
 196:     public String toString()
 197:     {
 198:       return "Narrow char: " + narrow + ", Wide char: " + wide;
 199:     }
 200: 
 201:     /**
 202:      * Write the code set profile information into the given input stream.
 203:      *
 204:      * @param profile a stream to write into.
 205:      */
 206:     public void write(AbstractCdrOutput profile)
 207:     {
 208:       AbstractCdrOutput encapsulation = profile.createEncapsulation();
 209:       narrow.write(encapsulation);
 210:       wide.write(encapsulation);
 211:       try
 212:         {
 213:           encapsulation.close();
 214:         }
 215:       catch (IOException ex)
 216:         {
 217:           throw new InternalError();
 218:         }
 219:     }
 220:   }
 221: 
 222:   /**
 223:    * The internet profile.
 224:    */
 225:   public class Internet_profile
 226:   {
 227:     /**
 228:      * The agreed tag for the Internet profile.
 229:      */
 230:     public static final int TAG_INTERNET_IOP = 0;
 231: 
 232:     /**
 233:      * The host.
 234:      */
 235:     public String host;
 236: 
 237:     /**
 238:      * The IIOP version (initialised to 1.2 by default).
 239:      */
 240:     public Version version = new Version(1, 2);
 241: 
 242:     /**
 243:      * The port.
 244:      */
 245:     public int port;
 246: 
 247:     /**
 248:      * The code sets component in the internet profile of this IOR. This is not
 249:      * a separate profile.
 250:      */
 251:     public CodeSets_profile CodeSets = new CodeSets_profile();
 252: 
 253:     /**
 254:      * Reserved for all components of this profile, this array holds the
 255:      * components other than code set components.
 256:      */
 257:     ArrayList components = new ArrayList();
 258: 
 259:     /**
 260:      * Return the human readable representation.
 261:      */
 262:     public String toString()
 263:     {
 264:       StringBuffer b = new StringBuffer();
 265:       b.append(host);
 266:       b.append(":");
 267:       b.append(port);
 268:       b.append(" (v");
 269:       b.append(version);
 270:       b.append(")");
 271:       if (components.size() > 0)
 272:         b.append(" " + components.size() + " extra components.");
 273:       return b.toString();
 274:     }
 275: 
 276:     /**
 277:      * Write the internet profile (except the heading tag.
 278:      */
 279:     public void write(AbstractCdrOutput out)
 280:     {
 281:       try
 282:         {
 283:           // Need to write the Internet profile into the separate
 284:           // stream as we must know the size in advance.
 285:           AbstractCdrOutput b = out.createEncapsulation();
 286: 
 287:           version.write(b);
 288:           b.write_string(host);
 289: 
 290:           b.write_ushort((short) (port & 0xFFFF));
 291: 
 292:           // Write the object key.
 293:           b.write_long(key.length);
 294:           b.write(key);
 295: 
 296:           // Number of the tagged components.
 297:           b.write_long(1 + components.size());
 298: 
 299:           b.write_long(CodeSets_profile.TAG_CODE_SETS);
 300:           CodeSets.write(b);
 301: 
 302:           TaggedComponent t;
 303: 
 304:           for (int i = 0; i < components.size(); i++)
 305:             {
 306:               t = (TaggedComponent) components.get(i);
 307:               TaggedComponentHelper.write(b, t);
 308:             }
 309: 
 310:           b.close();
 311:         }
 312:       catch (Exception e)
 313:         {
 314:           MARSHAL m = new MARSHAL("Unable to write Internet profile.");
 315:           m.minor = Minor.IOR;
 316:           m.initCause(e);
 317:           throw m;
 318:         }
 319:     }
 320:   }
 321: 
 322:   /**
 323:    * The standard minor code, indicating that the string to object converstio
 324:    * has failed due non specific reasons.
 325:    */
 326:   public static final int FAILED = 10;
 327: 
 328:   /**
 329:    * The internet profile of this IOR.
 330:    */
 331:   public Internet_profile Internet = new Internet_profile();
 332: 
 333:   /**
 334:    * The object repository Id.
 335:    */
 336:   public String Id;
 337: 
 338:   /**
 339:    * The object key.
 340:    */
 341:   public byte[] key;
 342: 
 343:   /**
 344:    * All tagged profiles of this IOR, except the separately defined Internet
 345:    * profile.
 346:    */
 347:   ArrayList profiles = new ArrayList();
 348: 
 349:   /**
 350:    * True if the profile was encoded using the Big Endian or the encoding is not
 351:    * known.
 352:    *
 353:    * false if it was encoded using the Little Endian.
 354:    */
 355:   public boolean Big_Endian = true;
 356: 
 357:   /**
 358:    * Create an empty instance, initialising the code sets to default values.
 359:    */
 360:   public IOR()
 361:   {
 362:   }
 363: 
 364:   /**
 365:    * Parse the provided stringifed reference.
 366:    *
 367:    * @param stringified_reference, in the form of IOR:nnnnnn.....
 368:    *
 369:    * @return the parsed IOR
 370:    *
 371:    * @throws BAD_PARAM, minor code 10, if the IOR cannot be parsed.
 372:    *
 373:    * TODO corballoc and other alternative formats.
 374:    */
 375:   public static IOR parse(String stringified_reference)
 376:     throws BAD_PARAM
 377:   {
 378:     try
 379:       {
 380:         if (!stringified_reference.startsWith("IOR:"))
 381:           throw new BAD_PARAM("The string refernce must start with IOR:",
 382:                               FAILED, CompletionStatus.COMPLETED_NO);
 383: 
 384:         IOR r = new IOR();
 385: 
 386:         ByteArrayOutputStream buf = new ByteArrayOutputStream();
 387:         String x = stringified_reference;
 388:         x = x.substring(x.indexOf(":") + 1);
 389: 
 390:         char cx;
 391: 
 392:         for (int i = 0; i < x.length(); i = i + 2)
 393:           {
 394:             cx = (char) Integer.parseInt(x.substring(i, i + 2), 16);
 395:             buf.write(cx);
 396:           }
 397: 
 398:         BufferredCdrInput cdr = new BufferredCdrInput(buf.toByteArray());
 399: 
 400:         r._read(cdr);
 401:         return r;
 402:       }
 403:     catch (Exception ex)
 404:       {
 405:         ex.printStackTrace();
 406:         throw new BAD_PARAM(ex + " while parsing " + stringified_reference,
 407:                             FAILED, CompletionStatus.COMPLETED_NO);
 408:       }
 409:   }
 410: 
 411:   /**
 412:    * Read the IOR from the provided input stream.
 413:    *
 414:    * @param c a stream to read from.
 415:    * @throws IOException if the stream throws it.
 416:    */
 417:   public void _read(AbstractCdrInput c)
 418:     throws IOException, BAD_PARAM
 419:   {
 420:     int endian;
 421: 
 422:     endian = c.read_long();
 423:     if (endian != 0)
 424:       {
 425:         Big_Endian = false;
 426:         c.setBigEndian(false);
 427:       }
 428:     _read_no_endian(c);
 429:   }
 430: 
 431:   /**
 432:    * Read the IOR from the provided input stream, not reading the endian data at
 433:    * the beginning of the stream. The IOR is thansferred in this form in
 434:    * {@link write_Object(org.omg.CORBA.Object)}.
 435:    *
 436:    * If the stream contains a null value, the Id and Internet fields become
 437:    * equal to null. Otherwise Id contains some string (possibly empty).
 438:    *
 439:    * Id is checked for null in AbstractCdrInput that then returns null instead of
 440:    * object.
 441:    *
 442:    * @param c a stream to read from.
 443:    * @throws IOException if the stream throws it.
 444:    */
 445:   public void _read_no_endian(AbstractCdrInput c)
 446:     throws IOException, BAD_PARAM
 447:   {
 448:     Id = c.read_string();
 449: 
 450:     int n_profiles = c.read_long();
 451: 
 452:     if (n_profiles == 0)
 453:       {
 454:         Id = null;
 455:         Internet = null;
 456:         return;
 457:       }
 458: 
 459:     for (int i = 0; i < n_profiles; i++)
 460:       {
 461:         int tag = c.read_long();
 462:         BufferredCdrInput profile = c.read_encapsulation();
 463: 
 464:         if (tag == Internet_profile.TAG_INTERNET_IOP)
 465:           {
 466:             Internet = new Internet_profile();
 467:             Internet.version = Version.read_version(profile);
 468:             Internet.host = profile.read_string();
 469:             Internet.port = profile.gnu_read_ushort();
 470: 
 471:             key = profile.read_sequence();
 472: 
 473:             // Read tagged components.
 474:             int n_components = 0;
 475: 
 476:             try
 477:               {
 478:                 if (Internet.version.since_inclusive(1, 1))
 479:                   n_components = profile.read_long();
 480: 
 481:                 for (int t = 0; t < n_components; t++)
 482:                   {
 483:                     int ctag = profile.read_long();
 484: 
 485:                     if (ctag == CodeSets_profile.TAG_CODE_SETS)
 486:                       {
 487:                         Internet.CodeSets.read(profile);
 488:                       }
 489:                     else
 490:                       {
 491:                         // Construct a generic component for codesets
 492:                         // profile.
 493:                         TaggedComponent pc = new TaggedComponent();
 494:                         pc.tag = ctag;
 495:                         pc.component_data = profile.read_sequence();
 496:                         Internet.components.add(pc);
 497:                       }
 498:                   }
 499:               }
 500:             catch (Unexpected ex)
 501:               {
 502:                 ex.printStackTrace();
 503:               }
 504:           }
 505:         else
 506:           {
 507:             // Construct a generic profile.
 508:             TaggedProfile p = new TaggedProfile();
 509:             p.tag = tag;
 510:             p.profile_data = profile.buffer.getBuffer();
 511: 
 512:             profiles.add(p);
 513:           }
 514:       }
 515:   }
 516: 
 517:   /**
 518:    * Write this IOR record to the provided CDR stream. This procedure writes the
 519:    * zero (Big Endian) marker first.
 520:    */
 521:   public void _write(AbstractCdrOutput out)
 522:   {
 523:     // Always use Big Endian.
 524:     out.write(0);
 525:     _write_no_endian(out);
 526:   }
 527: 
 528:   /**
 529:    * Write a null value to the CDR output stream.
 530:    *
 531:    * The null value is written as defined in OMG specification (zero length
 532:    * string, followed by an empty set of profiles).
 533:    */
 534:   public static void write_null(AbstractCdrOutput out)
 535:   {
 536:     // Empty Id string.
 537:     out.write_string("");
 538: 
 539:     // Empty set of profiles.
 540:     out.write_long(0);
 541:   }
 542: 
 543:   /**
 544:    * Write this IOR record to the provided CDR stream. The procedure writed data
 545:    * in Big Endian, but does NOT add any endian marker to the beginning.
 546:    */
 547:   public void _write_no_endian(AbstractCdrOutput out)
 548:   {
 549:     // Write repository id.
 550:     out.write_string(Id);
 551: 
 552:     out.write_long(1 + profiles.size());
 553: 
 554:     // Write the Internet profile.
 555:     out.write_long(Internet_profile.TAG_INTERNET_IOP);
 556:     Internet.write(out);
 557: 
 558:     // Write other profiles.
 559:     TaggedProfile tp;
 560: 
 561:     for (int i = 0; i < profiles.size(); i++)
 562:       {
 563:         tp = (TaggedProfile) profiles.get(i);
 564:         TaggedProfileHelper.write(out, tp);
 565:       }
 566:   }
 567: 
 568:   /**
 569:    * Returns a human readable string representation of this IOR object.
 570:    */
 571:   public String toString()
 572:   {
 573:     StringBuffer b = new StringBuffer();
 574:     b.append(Id);
 575:     b.append(" at ");
 576:     b.append(Internet);
 577: 
 578:     if (!Big_Endian)
 579:       b.append(" (Little endian) ");
 580: 
 581:     b.append(" Key ");
 582: 
 583:     for (int i = 0; i < key.length; i++)
 584:       {
 585:         b.append(Integer.toHexString(key[i] & 0xFF));
 586:       }
 587: 
 588:     b.append(" ");
 589:     b.append(Internet.CodeSets);
 590: 
 591:     return b.toString();
 592:   }
 593: 
 594:   /**
 595:    * Returs a stringified reference.
 596:    *
 597:    * @return a newly constructed stringified reference.
 598:    */
 599:   public String toStringifiedReference()
 600:   {
 601:     BufferedCdrOutput out = new BufferedCdrOutput();
 602: 
 603:     _write(out);
 604: 
 605:     StringBuffer b = new StringBuffer("IOR:");
 606: 
 607:     byte[] binary = out.buffer.toByteArray();
 608:     String s;
 609: 
 610:     for (int i = 0; i < binary.length; i++)
 611:       {
 612:         s = Integer.toHexString(binary[i] & 0xFF);
 613:         if (s.length() == 1)
 614:           b.append('0');
 615:         b.append(s);
 616:       }
 617: 
 618:     return b.toString();
 619:   }
 620: 
 621:   /**
 622:    * Adds a service-specific component to the IOR profile. The specified
 623:    * component will be included in all profiles, present in the IOR.
 624:    *
 625:    * @param tagged_component a tagged component being added.
 626:    */
 627:   public void add_ior_component(TaggedComponent tagged_component)
 628:   {
 629:     // Add to the Internet profile.
 630:     Internet.components.add(tagged_component);
 631: 
 632:     // Add to others.
 633:     for (int i = 0; i < profiles.size(); i++)
 634:       {
 635:         TaggedProfile profile = (TaggedProfile) profiles.get(i);
 636:         addComponentTo(profile, tagged_component);
 637:       }
 638:   }
 639: 
 640:   /**
 641:    * Adds a service-specific component to the IOR profile.
 642:    *
 643:    * @param tagged_component a tagged component being added.
 644:    *
 645:    * @param profile_id the IOR profile to that the component must be added. The
 646:    * 0 value ({@link org.omg.IOP.TAG_INTERNET_IOP#value}) adds to the Internet
 647:    * profile where host and port are stored by default.
 648:    */
 649:   public void add_ior_component_to_profile(TaggedComponent tagged_component,
 650:                                            int profile_id)
 651:   {
 652:     if (profile_id == TAG_INTERNET_IOP.value)
 653:       // Add to the Internet profile
 654:       Internet.components.add(tagged_component);
 655:     else
 656:       {
 657:         // Add to others.
 658:         for (int i = 0; i < profiles.size(); i++)
 659:           {
 660:             TaggedProfile profile = (TaggedProfile) profiles.get(i);
 661:             if (profile.tag == profile_id)
 662:               addComponentTo(profile, tagged_component);
 663:           }
 664:       }
 665:   }
 666: 
 667:   /**
 668:    * Add given component to the given profile that is NOT an Internet profile.
 669:    *
 670:    * @param profile the profile, where the component should be added.
 671:    * @param component the component to add.
 672:    */
 673:   private static void addComponentTo(TaggedProfile profile,
 674:                                      TaggedComponent component)
 675:   {
 676:     if (profile.tag == TAG_MULTIPLE_COMPONENTS.value)
 677:       {
 678:         TaggedComponent[] present;
 679:         if (profile.profile_data.length > 0)
 680:           {
 681:             BufferredCdrInput in = new BufferredCdrInput(profile.profile_data);
 682: 
 683:             present = new TaggedComponent[in.read_long()];
 684: 
 685:             for (int i = 0; i < present.length; i++)
 686:               {
 687:                 present[i] = TaggedComponentHelper.read(in);
 688:               }
 689:           }
 690:         else
 691:           present = new TaggedComponent[0];
 692: 
 693:         BufferedCdrOutput out = new BufferedCdrOutput(profile.profile_data.length
 694:                                             + component.component_data.length
 695:                                             + 8);
 696: 
 697:         // Write new amount of components.
 698:         out.write_long(present.length + 1);
 699: 
 700:         // Write other components.
 701:         for (int i = 0; i < present.length; i++)
 702:           TaggedComponentHelper.write(out, present[i]);
 703: 
 704:         // Write the passed component.
 705:         TaggedComponentHelper.write(out, component);
 706: 
 707:         try
 708:           {
 709:             out.close();
 710:           }
 711:         catch (IOException e)
 712:           {
 713:             throw new Unexpected(e);
 714:           }
 715:         profile.profile_data = out.buffer.toByteArray();
 716:       }
 717:     else
 718:       // The future supported tagged profiles should be added here.
 719:       throw new BAD_PARAM("Unsupported profile type " + profile.tag);
 720:   }
 721:   
 722:   /**
 723:    * Checks for equality.
 724:    */
 725:   public boolean equals(Object x)
 726:   {
 727:     if (x instanceof IOR)
 728:       {
 729:         boolean keys;
 730:         boolean hosts = true;
 731: 
 732:         IOR other = (IOR) x;
 733:         
 734:         if (Internet==null || other.Internet==null)
 735:           return Internet == other.Internet;
 736:         
 737:         if (key != null && other.key != null)
 738:           keys = Arrays.equals(key, other.key);
 739:         else
 740:           keys = key == other.key;
 741: 
 742:         if (Internet != null && Internet.host != null)
 743:           if (other.Internet != null && other.Internet.host != null)
 744:             hosts = other.Internet.host.equals(Internet.host);
 745: 
 746:         return keys & hosts && Internet.port==other.Internet.port;
 747:       }
 748:     else
 749:       return false;
 750:   }
 751:   
 752:   /**
 753:    * Get the hashcode of this IOR.
 754:    */
 755:   public int hashCode()
 756:   {
 757:     Adler32 adler = new Adler32();
 758:     if (key != null)
 759:       adler.update(key);
 760:     if (Internet != null)
 761:       {
 762:         if (Internet.host != null)
 763:           adler.update(Internet.host.getBytes());
 764:         adler.update(Internet.port);
 765:       }
 766:     return (int) adler.getValue();
 767:   }