1 /*
   2  * Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 /*
  26  * COMPONENT_NAME: idl.toJava
  27  *
  28  * ORIGINS: 27
  29  *
  30  * Licensed Materials - Property of IBM
  31  * 5639-D57 (C) COPYRIGHT International Business Machines Corp. 1997, 1999
  32  * RMI-IIOP v1.0
  33  *
  34  */
  35 
  36 package com.sun.tools.corba.se.idl.toJavaPortable;
  37 
  38 // NOTES:
  39 // -F46082.51<daz> Remove -stateful feature; javaStatefulName() obsolete.
  40 // -D57067 <klr> suppress default init if an emit init explicitly specified.
  41 // -D59071 <daz> Clone method entries when their content needs modification.
  42 // -D59092 <klr> Valuetype supporting interfaces should implement interface.
  43 // -D59418 <klr> Custom values implement org.omg.CORBA.CustomMarshal
  44 // -D59418 <klr> Invert read/read_Value, write/write_Value for Simon
  45 // -D60929 <klr> Update for RTF2.4 changes
  46 // -D62018 <klr> write_value for value with value field x calls xHelper.write.
  47 // -D62062 <klr> Add _write to value Helper to marshal state.
  48 //   write_value for value subclass calls parent._write
  49 // -D61650<daz> Remove '\n' from generated strings; use println()'s.
  50 
  51 import java.io.File;
  52 import java.io.PrintWriter;
  53 import java.util.Hashtable;
  54 import java.util.Enumeration;
  55 import java.util.Vector;
  56 
  57 import com.sun.tools.corba.se.idl.GenFileStream;
  58 import com.sun.tools.corba.se.idl.InterfaceEntry;
  59 import com.sun.tools.corba.se.idl.SymtabEntry;
  60 import com.sun.tools.corba.se.idl.TypedefEntry;
  61 import com.sun.tools.corba.se.idl.ValueEntry;
  62 import com.sun.tools.corba.se.idl.ValueBoxEntry;
  63 import com.sun.tools.corba.se.idl.InterfaceState;
  64 import com.sun.tools.corba.se.idl.MethodEntry;
  65 import com.sun.tools.corba.se.idl.PrimitiveEntry;
  66 import com.sun.tools.corba.se.idl.SequenceEntry;
  67 import com.sun.tools.corba.se.idl.StringEntry;
  68 import com.sun.tools.corba.se.idl.StructEntry;
  69 
  70 /**
  71  *
  72  **/
  73 public class ValueGen implements com.sun.tools.corba.se.idl.ValueGen, JavaGenerator
  74 {
  75   /**
  76    * Public zero-argument constructor.
  77    **/
  78   public ValueGen ()
  79   {
  80   } // ctor
  81 
  82   /**
  83    *
  84    **/
  85   public void generate (Hashtable symbolTable, ValueEntry v, PrintWriter str)
  86   {
  87     this.symbolTable = symbolTable;
  88     this.v = v;
  89     init ();
  90 
  91     openStream ();
  92     if (stream == null)
  93       return;
  94     generateTie ();
  95     generateHelper ();
  96     generateHolder ();
  97     writeHeading ();
  98     writeBody ();
  99     writeClosing ();
 100     closeStream ();
 101   } // generate
 102 
 103   /**
 104    * Initialize members unique to this generator.
 105    **/
 106   protected void init ()
 107   {
 108     emit = ((Arguments)Compile.compiler.arguments).emit;
 109     factories = (Factories)Compile.compiler.factories ();
 110   } // init
 111 
 112   /**
 113    *
 114    **/
 115   protected void openStream ()
 116   {
 117     stream = Util.stream (v, ".java");
 118   } // openStream
 119 
 120   /**
 121    * Generate a Tie class only when the user specifies the TIE option
 122    * and the valuetype does support an interface.
 123    **/
 124   protected void generateTie ()
 125   {
 126     boolean tie = ((Arguments)Compile.compiler.arguments).TIEServer;
 127     if (v.supports ().size () > 0  && tie)
 128     {
 129       Factories factories = (Factories)Compile.compiler.factories ();
 130       factories.skeleton ().generate (symbolTable, v);
 131     }
 132   } // generateTie
 133 
 134   /**
 135    *
 136    **/
 137   protected void generateHelper ()
 138   {
 139     ((Factories)Compile.compiler.factories ()).helper ().generate (symbolTable, v);
 140   } // generateHelper
 141 
 142   /**
 143    *
 144    **/
 145   protected void generateHolder ()
 146   {
 147     ((Factories)Compile.compiler.factories ()).holder ().generate (symbolTable, v);
 148   } // generateHolder
 149 
 150   /**
 151    *
 152    **/
 153   protected void writeHeading ()
 154   {
 155     Util.writePackage (stream, v);
 156     Util.writeProlog (stream, ((GenFileStream)stream).name ());
 157 
 158     if (v.comment () != null)
 159       v.comment ().generate ("", stream);
 160 
 161     if (v.isAbstract ())
 162     {
 163       writeAbstract ();
 164       return;
 165     }
 166     else
 167       stream.print ("public class " + v.name ());
 168 
 169     // There should always be at least one parent: ValueBase
 170     SymtabEntry parent = (SymtabEntry) v.derivedFrom ().elementAt (0);
 171 
 172     // If parent is ValueBase, it's mapped to java.io.Serializable
 173     String parentName = Util.javaName (parent);
 174     boolean impl = false;
 175 
 176     if (parentName.equals ("java.io.Serializable"))
 177     {
 178 //    stream.print (" implements org.omg.CORBA.portable.ValueBase, org.omg.CORBA.portable.Streamable");
 179       stream.print (" implements org.omg.CORBA.portable.ValueBase"); // <d60929>
 180       impl = true;
 181     }
 182     else if ( !((ValueEntry)parent).isAbstract ())
 183       stream.print (" extends " + parentName);
 184 
 185     // if inheriting from abstract values
 186     for (int i = 0; i < v.derivedFrom ().size (); i++) {
 187       parent = (SymtabEntry) v.derivedFrom ().elementAt (i);
 188       if ( ((ValueEntry)parent).isAbstract ())
 189       {
 190         if (!impl)
 191         {
 192           stream.print (" implements ");
 193           impl = true;
 194         }
 195         else
 196           stream.print (", ");
 197         stream.print (Util.javaName (parent));
 198       }
 199     }
 200 // <d59092-klr> Valuetype supporting interface implement Operations interface
 201 // for supported IDL interface
 202     if (((ValueEntry)v).supports ().size () > 0) {
 203       if (!impl)
 204       {
 205         stream.print (" implements ");
 206         impl = true;
 207       }
 208       else
 209         stream.print (", ");
 210 
 211       InterfaceEntry s =(InterfaceEntry)((ValueEntry)v).supports().elementAt(0);
 212       // abstract supported classes don't have "Operations"
 213       if (s.isAbstract ())
 214          stream.print (Util.javaName (s));
 215       else
 216           stream.print (Util.javaName (s) + "Operations");
 217       }
 218 
 219 //  <d59418> Custom valuetypes implement org.omg.CORBA.CustomMarshal.
 220     if ( ((ValueEntry)v).isCustom ()) {
 221       if (!impl)
 222       {
 223         stream.print (" implements ");
 224         impl = true;
 225       }
 226       else
 227         stream.print (", ");
 228 
 229       stream.print ("org.omg.CORBA.CustomMarshal ");
 230       }
 231 
 232     stream.println ();
 233     stream.println ("{");
 234   } // writeHeading
 235 
 236   /**
 237    *
 238    **/
 239   protected void writeBody ()
 240   {
 241     writeMembers ();
 242     writeInitializers ();
 243     writeConstructor (); // <d57067>
 244     writeTruncatable (); // <d60929>
 245     writeMethods ();
 246   } // writeBody
 247 
 248   /**
 249    *
 250    **/
 251   protected void writeClosing ()
 252   {
 253    if (v.isAbstract ())
 254      stream.println ("} // interface " + v.name ());
 255    else
 256      stream.println ("} // class " + v.name ());
 257   } // writeClosing
 258 
 259   /**
 260    *
 261    **/
 262   protected void closeStream ()
 263   {
 264     stream.close ();
 265   } // closeStream
 266 
 267   /**
 268    *
 269    **/
 270   protected void writeConstructor ()
 271   {
 272    // Per Simon, 9/3/98, emit a protected default constructor
 273    if (!v.isAbstract () && !explicitDefaultInit) { // <d57067 - klr>
 274         stream.println ("  protected " + v.name () + " () {}");
 275         stream.println ();
 276     }
 277   } // writeConstructor
 278 
 279   /**
 280    *
 281    **/
 282   protected void writeTruncatable () // <d60929>
 283   {
 284    // Per Simon, 4/6/98, emit _truncatable_ids()
 285    if (!v.isAbstract ()) {
 286         stream.println ("  public String[] _truncatable_ids() {");
 287         stream.println ("      return " + Util.helperName(v, true) + ".get_instance().get_truncatable_base_ids();"); // <d61056>
 288         stream.println ("  }");
 289         stream.println ();
 290     }
 291   } // writeTruncatable
 292 
 293   /**
 294    *
 295    **/
 296   protected void writeMembers ()
 297   {
 298     // if the value type contains no data members, a null return is expected
 299     if (v.state () == null)
 300       return;
 301 
 302     for (int i = 0; i < v.state ().size (); i ++)
 303     {
 304       InterfaceState member = (InterfaceState) v.state ().elementAt (i);
 305       SymtabEntry entry = (SymtabEntry) member.entry;
 306       Util.fillInfo (entry);
 307 
 308       if (entry.comment () != null)
 309         entry.comment ().generate (" ", stream);
 310 
 311       String modifier = "  ";
 312       if (member.modifier == InterfaceState.Public)
 313         modifier = "  public ";
 314       Util.writeInitializer (modifier, entry.name (), "", entry, stream);
 315     }
 316   } // writeMembers
 317 
 318   /**
 319    *
 320    **/
 321   protected void writeInitializers ()
 322   {
 323     Vector init = v.initializers ();
 324     if (init != null)
 325     {
 326       stream.println ();
 327       for (int i = 0; i < init.size (); i++)
 328       {
 329         MethodEntry element = (MethodEntry) init.elementAt (i);
 330         element.valueMethod (true);
 331         ((MethodGen) element.generator ()). interfaceMethod (symbolTable, element, stream);
 332         if (element.parameters ().isEmpty ()) // <d57067-klr>
 333           explicitDefaultInit = true;
 334       }
 335     }
 336   } // writeInitializers
 337 
 338   /**
 339    *
 340    **/
 341   protected void writeMethods ()
 342   {
 343     // contained vector contains methods, attributes, const, enums, exceptions,
 344     // structs, unions, or typedefs that are declared inside the value object.
 345     // State members of the nested types are also included in this vector.
 346     // Thus, if the declaration of a constructed type is nested in the decl.
 347     // of a state member, e.g   struct x {boolean b;}  memberx;
 348     // the generation of the nested type must be handled here.
 349     Enumeration e = v.contained ().elements ();
 350     while (e.hasMoreElements ())
 351     {
 352       SymtabEntry contained = (SymtabEntry)e.nextElement ();
 353       if (contained instanceof MethodEntry)
 354       {
 355         MethodEntry element = (MethodEntry)contained;
 356         ((MethodGen)element.generator ()).interfaceMethod (symbolTable, element, stream);
 357       }
 358       else
 359       {
 360         // Generate the type referenced by the typedef.
 361         if (contained instanceof TypedefEntry)
 362           contained.type ().generate (symbolTable, stream);
 363 
 364         // Note that we also need to generate the typedef itself if
 365         // contained is a typedef.
 366         contained.generate (symbolTable, stream);
 367       }
 368     }
 369 
 370     // Abstract values are mapped to interfaces. There is no need to generate
 371     // the bindings for inheriting methods in case of inheritance from other
 372     // abstract values or supporting interface
 373     if (v.isAbstract ())
 374         return;
 375 
 376     // workaround: if the value type doesnot support any interfaces, a null
 377     // return is expected instead of an empty vector
 378 
 379     // if supporting an interfaces, generate bindings for inheriting methods
 380     if (v.supports ().size () > 0)
 381     {
 382       InterfaceEntry intf = (InterfaceEntry) v.supports ().elementAt (0);
 383       Enumeration el = intf.allMethods ().elements ();
 384       while (el.hasMoreElements ())
 385       {
 386         MethodEntry m = (MethodEntry) el.nextElement ();
 387         // <d59071> Don't alter the symbol table/emit list elements!
 388         //m.container (v);
 389         //((MethodGen)m.generator ()).interfaceMethod (symbolTable, m, stream);
 390         MethodEntry mClone = (MethodEntry)m.clone ();
 391         mClone.container (v);
 392         ((MethodGen)mClone.generator ()).interfaceMethod (symbolTable, mClone, stream);
 393       }
 394     }
 395 
 396     // if inheriting from abstract values, generating bindings for all
 397     // inheriting methods
 398     for (int i = 0; i < v.derivedFrom ().size (); i++) {
 399       ValueEntry parentValue = (ValueEntry) v.derivedFrom ().elementAt (i);
 400       if (parentValue.isAbstract ())
 401       {
 402         Enumeration el = parentValue.allMethods ().elements ();
 403         while (el.hasMoreElements ())
 404         {
 405            MethodEntry m = (MethodEntry) el.nextElement ();
 406           // <d59071> Don't alter the symbol table/emit list elements!
 407           //m.container (v);
 408           //((MethodGen)m.generator ()).interfaceMethod (symbolTable, m, stream);
 409           MethodEntry mClone = (MethodEntry)m.clone ();
 410           mClone.container (v);
 411           ((MethodGen)mClone.generator ()).interfaceMethod (symbolTable, mClone, stream);
 412         }
 413       }
 414     }
 415 
 416   //writeStreamableMethods ();
 417   } // writeMethods
 418 
 419   /**
 420    *
 421    **/
 422   protected void writeStreamableMethods ()
 423   {
 424     stream.println ("  public void _read (org.omg.CORBA.portable.InputStream istream)");
 425     stream.println ("  {");
 426     read (0, "    ", "this", v, stream);
 427     stream.println ("  }");
 428     stream.println ();
 429     stream.println ("  public void _write (org.omg.CORBA.portable.OutputStream ostream)");
 430     stream.println ("  {");
 431     write (0, "    ", "this", v, stream);
 432     stream.println ("  }");
 433     stream.println ();
 434     stream.println ("  public org.omg.CORBA.TypeCode _type ()");
 435     stream.println ("  {");
 436     stream.println ("    return " + Util.helperName (v, false) + ".type ();"); // <d61056>
 437     stream.println ("  }");
 438   } // writeStreamableMethods
 439 
 440   ///////////////
 441   // From JavaGenerator
 442 
 443   public int helperType (int index, String indent, TCOffsets tcoffsets, String name, SymtabEntry entry, PrintWriter stream)
 444   {
 445     ValueEntry vt = (ValueEntry) entry;
 446     Vector state = vt.state ();
 447     int noOfMembers = state == null ? 0 : state.size ();
 448     String members = "_members" + index++;
 449     String tcOfMembers = "_tcOf" + members;
 450 
 451     stream.println (indent + "org.omg.CORBA.ValueMember[] "
 452                     + members + " = new org.omg.CORBA.ValueMember["
 453                     + noOfMembers
 454                     + "];");
 455     stream.println (indent + "org.omg.CORBA.TypeCode " + tcOfMembers + " = null;");
 456     //stream.println (""); // <d61650>
 457 
 458     String definedInrepId = "_id";
 459     String repId, version;
 460 
 461     for (int k=0; k<noOfMembers; k++)
 462     {
 463       InterfaceState valueMember = (InterfaceState)state.elementAt (k);
 464       TypedefEntry member = (TypedefEntry)valueMember.entry;
 465       SymtabEntry mType = Util.typeOf (member);
 466       if (hasRepId (member))
 467       {
 468         repId = Util.helperName (mType, true) + ".id ()"; // <d61056>
 469         if (mType instanceof ValueEntry || mType instanceof ValueBoxEntry)
 470           // OBV spec is silent on defining VersionSpec for valuetype RepIds
 471           version = "\"\"";
 472         else
 473         {
 474           String id = mType.repositoryID ().ID ();
 475           version = '"' + id.substring (id.lastIndexOf (':')+1) + '"';
 476         }
 477       }
 478       else
 479       {
 480         repId = "\"\"";
 481         version = "\"\"";
 482       }
 483 
 484       // Get TypeCode for valuetype member and store it var. name given by tcOfMembers
 485       stream.println (indent + "// ValueMember instance for " + member.name ());
 486       index = ((JavaGenerator)member.generator ()).type (index, indent, tcoffsets, tcOfMembers, member, stream);
 487       stream.println (indent + members + "[" + k + "] = new org.omg.CORBA.ValueMember ("  // <d61650>
 488           + '"' + member.name () + "\", ");                               // name
 489       stream.println (indent + "    " + repId + ", ");                    // id
 490       stream.println (indent + "    " + definedInrepId + ", ");           // defined_in
 491       stream.println (indent + "    " + version + ", ");                  // version
 492       stream.println (indent + "    " + tcOfMembers + ", ");              // type
 493       stream.println (indent + "    " + "null, ");                        // type_def
 494       stream.println (indent + "    " + "org.omg.CORBA." +
 495           (valueMember.modifier == InterfaceState.Public ?
 496               "PUBLIC_MEMBER" : "PRIVATE_MEMBER") + ".value" + ");");     // access
 497     } // end for
 498 
 499     stream.println (indent + name + " = org.omg.CORBA.ORB.init ().create_value_tc ("
 500                     + "_id, "
 501                     + '"' + entry.name () + "\", "
 502                     + getValueModifier (vt) + ", "
 503                     + getConcreteBaseTypeCode (vt) + ", "
 504                     + members
 505                     + ");");
 506 
 507     return index;
 508   } // helperType
 509 
 510   public int type (int index, String indent, TCOffsets tcoffsets, String name, SymtabEntry entry, PrintWriter stream) {
 511     stream.println (indent + name + " = " + Util.helperName (entry, true) + ".type ();"); // <d61056>
 512     return index;
 513   } // type
 514 
 515   // Check for types which don't have a Repository ID: primitive,
 516   // string, arrays and sequences.
 517 
 518   private static boolean hasRepId (SymtabEntry member)
 519   {
 520     SymtabEntry mType = Util.typeOf (member);
 521     return !( mType instanceof PrimitiveEntry ||
 522               mType instanceof StringEntry ||
 523               ( mType instanceof TypedefEntry &&
 524                 !(((TypedefEntry)mType).arrayInfo ().isEmpty ()) ) ||
 525               ( mType instanceof TypedefEntry && member.type () instanceof SequenceEntry) );
 526   } // hasRepId
 527 
 528   private static String getValueModifier (ValueEntry vt)
 529   {
 530     String mod = "NONE";
 531     if (vt.isCustom ())
 532       mod = "CUSTOM";
 533     else if (vt.isAbstract ())
 534       mod = "ABSTRACT";
 535     else if (vt.isSafe ())
 536       mod = "TRUNCATABLE";
 537     return "org.omg.CORBA.VM_" + mod + ".value";
 538   } // getValueModifier
 539 
 540   private static String getConcreteBaseTypeCode (ValueEntry vt)
 541   {
 542     Vector v = vt.derivedFrom ();
 543     if (!vt.isAbstract ())
 544     {
 545       SymtabEntry base = (SymtabEntry)vt.derivedFrom ().elementAt (0);
 546       if (!"ValueBase".equals (base.name ()))
 547         return Util.helperName (base, true) + ".type ()"; // <d61056>
 548     }
 549     return "null";
 550   } // getConcreteBaseTypeCode
 551 
 552   public void helperRead (String entryName, SymtabEntry entry, PrintWriter stream)
 553   {
 554   // <d59418 - KLR> per Simon, make "static" read call istream.read_value.
 555   //                put real marshalling code in read_value.
 556 
 557     if (((ValueEntry)entry).isAbstract ())
 558     {
 559       stream.println ("    throw new org.omg.CORBA.BAD_OPERATION (\"abstract value cannot be instantiated\");");
 560     }
 561     else
 562     {
 563     stream.println ("    return (" + entryName +") ((org.omg.CORBA_2_3.portable.InputStream) istream).read_value (get_instance());"); // <d60929>
 564     }
 565     stream.println ("  }");
 566     stream.println ();
 567 
 568     // done with "read", now do "read_value with real marshalling code.
 569 
 570     stream.println ("  public java.io.Serializable read_value (org.omg.CORBA.portable.InputStream istream)"); // <d60929>
 571     stream.println ("  {");
 572 
 573     // per Simon, 3/3/99, read_value for custom values throws an exception
 574     if (((ValueEntry)entry).isAbstract ())
 575     {
 576       stream.println ("    throw new org.omg.CORBA.BAD_OPERATION (\"abstract value cannot be instantiated\");");
 577     }
 578     else
 579       if (((ValueEntry)entry).isCustom ())
 580       {
 581         stream.println ("    throw new org.omg.CORBA.BAD_OPERATION (\"custom values should use unmarshal()\");");
 582       }
 583       else
 584       {
 585         stream.println ("    " + entryName + " value = new " + entryName + " ();");
 586         read (0, "    ", "value", entry, stream);
 587         stream.println ("    return value;");
 588       }
 589     stream.println ("  }");
 590     stream.println ();
 591     // End of normal read method
 592 
 593     // Per Simon, 8/26/98 - Value helpers get an additional overloaded
 594     // read method where the value is passed in instead of "new'd" up. This is
 595     // used for reading parent value state.
 596 
 597     // Per Simon, 3/3/99 - Don't change this "read" for custom marshalling
 598     stream.println ("  public static void read (org.omg.CORBA.portable.InputStream istream, " + entryName + " value)");
 599     stream.println ("  {");
 600     read (0, "    ", "value", entry, stream);
 601   } // helperRead
 602 
 603   public int read (int index, String indent, String name, SymtabEntry entry, PrintWriter stream)
 604   {
 605     // First do the state members from concrete parent hierarchy
 606     Vector vParents = ((ValueEntry) entry).derivedFrom ();
 607     if (vParents != null && vParents.size() != 0)
 608     {
 609       ValueEntry parent = (ValueEntry) vParents.elementAt (0);
 610       if (parent == null)
 611         return index;
 612       // Per Simon, 4/6/99 - call parent read. <d60929>
 613       if (! Util.javaQualifiedName(parent).equals ("java.io.Serializable")) // <d60929>
 614           stream.println(indent + Util.helperName (parent, true) + ".read (istream, value);"); // <d60929> // <d61056>
 615     }
 616 
 617     Vector vMembers = ((ValueEntry) entry).state ();
 618     int noOfMembers = vMembers == null ? 0 : vMembers.size ();
 619 
 620     for (int k = 0; k < noOfMembers; k++)
 621     {
 622       TypedefEntry member = (TypedefEntry)((InterfaceState)vMembers.elementAt (k)).entry;
 623       String memberName = member.name ();
 624       SymtabEntry mType = member.type ();
 625 
 626       if (mType instanceof PrimitiveEntry ||
 627           mType instanceof TypedefEntry   ||
 628           mType instanceof SequenceEntry  ||
 629           mType instanceof StringEntry    ||
 630           !member.arrayInfo ().isEmpty ())
 631         index = ((JavaGenerator)member.generator ()).read (index, indent, name + '.' + memberName, member, stream);
 632       else if (mType instanceof ValueEntry)
 633       {
 634         String returnType = Util.javaQualifiedName (mType);
 635         if (mType instanceof ValueBoxEntry)
 636           // <f46082.51> Remove -stateful.
 637           //returnType = Util.javaStatefulName (mType);
 638           returnType = Util.javaName (mType);
 639         stream.println ("    " + name + '.' + memberName + " = (" + returnType +
 640                         ") ((org.omg.CORBA_2_3.portable.InputStream)istream).read_value (" + Util.helperName (mType, true) +  // <d61056>
 641                         ".get_instance ());"); // <d61056>
 642       }
 643       else
 644         stream.println (indent + name + '.' + memberName + " = " +
 645                         Util.helperName (mType, true) + ".read (istream);"); // <d61056>
 646     }
 647 
 648     return index;
 649   } // read
 650 
 651   public void helperWrite (SymtabEntry entry, PrintWriter stream)
 652   {
 653     // <d59418 - KLR> per Simon, make "static" write call istream.write_value.
 654     //              put real marshalling code in write_value.
 655     stream.println ("    ((org.omg.CORBA_2_3.portable.OutputStream) ostream).write_value (value, get_instance());"); // <d60929>
 656     stream.println ("  }");
 657     stream.println ();
 658 
 659     // <d62062>
 660     // per Simon, 4/27/99, add static _write that marshals the state of this
 661     //  value for non-custom valuetypes
 662     if (!((ValueEntry)entry).isCustom ())
 663     {
 664        stream.println ("  public static void _write (org.omg.CORBA.portable.OutputStream ostream, " + Util.javaName (entry) + " value)");
 665        stream.println ("  {");
 666        write (0, "    ", "value", entry, stream);
 667        stream.println ("  }");
 668        stream.println ();
 669     }
 670 
 671     // done with "_write", now do "write_value
 672     stream.println ("  public void write_value (org.omg.CORBA.portable.OutputStream ostream, java.io.Serializable obj)"); // <d60929>
 673     stream.println ("  {");
 674 
 675     // per Simon, 3/3/99, write_value for custom values throws an exception
 676     if (((ValueEntry)entry).isCustom ())
 677     {
 678       stream.println ("    throw new org.omg.CORBA.BAD_OPERATION (\"custom values should use marshal()\");");
 679     }
 680     else {
 681       String entryName = Util.javaName(entry);
 682       stream.println ("    _write (ostream, (" + entryName + ") obj);"); // <d62062>
 683 //      write (0, "    ", "value", entry, stream); <d62062>
 684     }
 685   } // helperWrite
 686 
 687   public int write (int index, String indent, String name, SymtabEntry entry, PrintWriter stream)
 688   {
 689     // First do the state members from concrete parent hierarchy
 690     Vector vParents = ((ValueEntry)entry).derivedFrom ();
 691     if (vParents != null && vParents.size () != 0)
 692     {
 693       ValueEntry parent = (ValueEntry)vParents.elementAt (0);
 694       if (parent == null)
 695         return index;
 696       // Per Simon, 4/06/99 - call parent write. <d60929>
 697       // Per Simon, 4/27/99 - call parent _write. <d62062>
 698       if (! Util.javaQualifiedName(parent).equals ("java.io.Serializable")) // <d60929>
 699           stream.println(indent + Util.helperName (parent, true) + "._write (ostream, value);"); // <d60929> <d61056> <d62062>
 700     }
 701 
 702     Vector vMembers = ((ValueEntry) entry ).state ();
 703     int noOfMembers = vMembers == null ? 0 : vMembers.size ();
 704     for (int k = 0; k < noOfMembers; k++)
 705     {
 706       TypedefEntry member = (TypedefEntry)((InterfaceState)vMembers.elementAt (k)).entry;
 707       String memberName = member.name ();
 708       SymtabEntry mType = member.type ();
 709 
 710       if (mType instanceof PrimitiveEntry ||
 711           mType instanceof TypedefEntry   ||
 712           mType instanceof SequenceEntry  ||
 713           mType instanceof StringEntry    ||
 714           !member.arrayInfo ().isEmpty ())
 715         index = ((JavaGenerator)member.generator ()).write (index, indent, name + '.' + memberName, member, stream);
 716       else
 717         stream.println (indent + Util.helperName (mType, true) + // <d61056>
 718                               ".write (ostream, " + name + '.' + memberName + ");");
 719     }
 720 
 721     return index;
 722   } // write
 723 
 724   /**
 725    *
 726    **/
 727   protected void writeAbstract ()
 728   {
 729     stream.print ("public interface " + v.name ());
 730 
 731     // workaround: if the abstract value type does not have any parent, a vector
 732     // containing ValueBase should be returned instead of an empty vector
 733     if (v.derivedFrom ().size () == 0)
 734       stream.print (" extends org.omg.CORBA.portable.ValueBase"); // <d60929>
 735     else
 736     {
 737       SymtabEntry parent;
 738       // list the values the abstract value type inherits
 739       for (int i = 0; i < v.derivedFrom ().size (); i++)
 740       {
 741         if (i == 0)
 742            stream.print (" extends ");
 743         else
 744            stream.print (", ");
 745         parent = (SymtabEntry) v.derivedFrom ().elementAt (i);
 746         stream.print (Util.javaName (parent));
 747       }
 748     }
 749 
 750     // list the interface the abstract value type supports
 751     if (v.supports ().size () > 0)
 752     {
 753       stream.print (", ");
 754       SymtabEntry intf = (SymtabEntry) v.supports ().elementAt (0);
 755       stream.print (Util.javaName (intf));
 756     }
 757     stream.println ();
 758     stream.println ("{");
 759   }
 760 
 761   protected int emit = 0;
 762   protected Factories factories   = null;
 763   protected Hashtable  symbolTable = null;
 764   protected ValueEntry v = null;
 765   protected PrintWriter stream = null;
 766   protected boolean explicitDefaultInit = false; // <d57067 - klr>
 767 } // class ValueGen