Helper.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 1999, 2004, 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
36package com.sun.tools.corba.se.idl.toJavaPortable;
37
38// NOTES:
39// -F46082.51<daz> Remove -stateful feature.
40// -D57118   <klr> Fix "narrow" in helper for abstract interface
41// -D58889   <klr> re-Fix "narrow" in helper for abstract interface
42// -D59383   <klr> 'get_class' in value helper returns value class, not helper.
43// -D59413   <klr> Remove Helper interface references for non-value types.
44// -D59435   <klr> Remove read_Object, write_Object completely.
45// -D59418   <klr> Move read_Value, write_Value to generator's helperRead.
46
47import java.io.PrintWriter;
48
49import java.util.Enumeration;
50import java.util.Vector;
51
52import com.sun.tools.corba.se.idl.GenFileStream;
53import com.sun.tools.corba.se.idl.InterfaceEntry;
54import com.sun.tools.corba.se.idl.MethodEntry;
55import com.sun.tools.corba.se.idl.ParameterEntry;
56import com.sun.tools.corba.se.idl.SymtabEntry;
57import com.sun.tools.corba.se.idl.ValueEntry;
58import com.sun.tools.corba.se.idl.ValueBoxEntry;
59import com.sun.tools.corba.se.idl.TypedefEntry;
60import com.sun.tools.corba.se.idl.InterfaceState;
61import com.sun.tools.corba.se.idl.PrimitiveEntry;
62import com.sun.tools.corba.se.idl.StructEntry;
63
64/**
65 *
66 **/
67public class Helper implements AuxGen
68{
69  /**
70   * Public zero-argument constructor.
71   **/
72  public Helper ()
73  {
74  } // ctor
75
76  /**
77   * Generate the helper class.  Provides general algorithm
78   * for auxiliary binding generation:
79   *
80   * 1.) Initialize symbol table and symbol table entry members,
81   *     common to all generators.
82   * 2.) Initialize members unique to this generator.
83   * 3.) Open print stream
84   * 4.) Write class heading: package, prologue, class statement, open curly
85   * 5.) Write class body: member data and methods
86   * 6.) Write class closing: close curly
87   * 7.) Close the print stream
88   **/
89  public void generate (java.util.Hashtable symbolTable, com.sun.tools.corba.se.idl.SymtabEntry entry)
90  {
91    this.symbolTable = symbolTable;
92    this.entry       = entry;
93    init ();
94
95    openStream ();
96    if (stream == null)
97      return;
98    writeHeading ();
99    writeBody ();
100    writeClosing ();
101    closeStream ();
102  } // generate
103
104  /**
105   * Initialize variables unique to this generator.
106   **/
107  protected void init ()
108  {
109    helperClass = entry.name () + "Helper";
110    if (entry instanceof ValueBoxEntry)
111    {
112      ValueBoxEntry v = (ValueBoxEntry) entry;
113      TypedefEntry member = ((InterfaceState) v.state ().elementAt (0)).entry;
114      SymtabEntry mType =  member.type ();
115
116      if (mType instanceof PrimitiveEntry)
117        helperType = Util.javaName (entry);
118      else
119        helperType = Util.javaName (mType);
120    }
121    else
122      helperType = Util.javaName (entry);
123  } // init
124
125  /**
126   * Open the print stream for subsequent output.
127   **/
128  protected void openStream ()
129  {
130    stream = Util.stream (entry, "Helper.java");
131  } // openStream
132
133  /**
134   * Generate the heading, including package, imports, class statements,
135   * and open curly.
136   **/
137  protected void writeHeading ()
138  {
139    Util.writePackage (stream, entry, Util.HelperFile);
140    Util.writeProlog (stream, stream.name ());
141
142    // Transfer comment to target <30jul1997daz>.
143    if (entry.comment () != null)
144      entry.comment ().generate ("", stream);
145
146    stream.print ("public final class " + helperClass);
147    if (entry instanceof ValueEntry)
148      stream.println (" implements org.omg.CORBA.portable.ValueHelper");
149    else
150      stream.println ();
151    stream.println ('{');
152  }
153
154  /**
155   * Generate members of this class.
156   **/
157  protected void writeBody ()
158  {
159    writeInstVars ();
160    writeCtors ();
161    writeInsert ();
162    writeExtract ();
163    writeType ();
164    writeID ();
165    writeRead ();
166    writeWrite ();
167    if (entry instanceof InterfaceEntry && !(entry instanceof ValueEntry)) {
168      writeNarrow ();
169      writeUncheckedNarrow ();
170    }
171    writeHelperInterface ();
172    if (entry instanceof ValueEntry)
173      writeValueHelperInterface ();
174  } // writeBody
175
176  /**
177   * Generate members of the Helper interface.
178   **/
179  protected void writeHelperInterface ()
180  {
181  } // writeHelperInterface
182
183  /**
184   * Generate members of the ValueHelper interface.
185   **/
186  protected void writeValueHelperInterface ()
187  {
188    writeGetID ();       // moved for <d59413>
189    writeGetType ();     // moved for <d59413>
190    writeGetInstance (); // not in ValueHelper interface
191    writeGetClass ();
192    writeGetSafeBaseIds ();
193  } // writeHelperInterface
194
195  /**
196   * Generate the closing statements.
197   **/
198  protected void writeClosing ()
199  {
200    stream.println ('}');
201  }
202
203  /**
204   * Write the stream to file by closing the print stream.
205   **/
206  protected void closeStream ()
207  {
208    stream.close ();
209  }
210
211  /**
212   * Generate the instance variables.
213   **/
214  protected void writeInstVars ()
215  {
216    stream.println ("  private static String  _id = \"" + Util.stripLeadingUnderscoresFromID (entry.repositoryID ().ID ()) + "\";");
217    if (entry instanceof ValueEntry)
218    {
219      stream.println ();
220      stream.println ("  private static " + helperClass + " helper = new " + helperClass + " ();");
221      stream.println ();
222      stream.println ("  private static String[] _truncatable_ids = {");
223      stream.print   ("    _id");
224
225      // Any safe ValueEntry must have a concete value parent.
226      // The topmost parent cannot be safe since it doesn't have
227      // a concrete parent.
228      ValueEntry child = (ValueEntry) entry;
229      while (child.isSafe ())
230      {
231        stream.println(",");
232        ValueEntry parent = (ValueEntry)child.derivedFrom ().elementAt (0);
233        stream.print("    \"" + Util.stripLeadingUnderscoresFromID (parent.repositoryID ().ID ()) + "\"");
234        child = parent;
235      }
236      stream.println("   };");
237    }
238    stream.println ();
239  } // writeInstVars
240
241  /**
242   * Generate the constructors.
243   **/
244  protected void writeCtors ()
245  {
246    stream.println ("  public " + helperClass + "()");
247    stream.println ("  {");
248    stream.println ("  }");
249    stream.println ();
250  } // writeCtors
251
252  /**
253   * Generate the insert method.
254   **/
255  protected void writeInsert ()
256  {
257    stream.println ("  public static void insert (org.omg.CORBA.Any a, " + helperType + " that)");
258    stream.println ("  {");
259    stream.println ("    org.omg.CORBA.portable.OutputStream out = a.create_output_stream ();");
260    stream.println ("    a.type (type ());");
261    stream.println ("    write (out, that);");
262    stream.println ("    a.read_value (out.create_input_stream (), type ());");
263    stream.println ("  }");
264    stream.println ();
265  } // writeInsert
266
267  /**
268   * Generate the extract method.
269   **/
270  protected void writeExtract ()
271  {
272    stream.println ("  public static " + helperType + " extract (org.omg.CORBA.Any a)");
273    stream.println ("  {");
274    stream.println ("    return read (a.create_input_stream ());");
275    stream.println ("  }");
276    stream.println ();
277  } // writeExtract
278
279  /**
280   * Generate the typecode variable and type method.
281   **/
282  protected void writeType ()
283  {
284    boolean canRecurse = entry instanceof ValueEntry
285        || entry instanceof ValueBoxEntry
286        || entry instanceof StructEntry;
287    stream.println ("  private static org.omg.CORBA.TypeCode __typeCode = null;");
288    if (canRecurse)
289      stream.println ("  private static boolean __active = false;");
290    stream.println ("  synchronized public static org.omg.CORBA.TypeCode type ()");
291    stream.println ("  {");
292    stream.println ("    if (__typeCode == null)");
293    stream.println ("    {");
294    if (canRecurse) {
295    stream.println ("      synchronized (org.omg.CORBA.TypeCode.class)");
296    stream.println ("      {");
297    stream.println ("        if (__typeCode == null)");
298    stream.println ("        {");
299    stream.println ("          if (__active)");
300    stream.println ("          {");
301    stream.println ("            return org.omg.CORBA.ORB.init().create_recursive_tc ( _id );");
302    stream.println ("          }");
303    stream.println ("          __active = true;");
304    ((JavaGenerator)entry.generator ()).helperType (0, "          ", new TCOffsets (), "__typeCode", entry, stream);
305    }
306    else
307    ((JavaGenerator)entry.generator ()).helperType (0, "      ", new TCOffsets (), "__typeCode", entry, stream);
308
309    // Generate body of type() method
310
311    if (canRecurse) {
312    stream.println ("          __active = false;");
313    stream.println ("        }");
314    stream.println ("      }");
315    }
316    stream.println ("    }");
317    stream.println ("    return __typeCode;");
318    stream.println ("  }");
319    stream.println ();
320  } // writeType
321
322  /**
323   * Generate the ID method.
324   **/
325  protected void writeID ()
326  {
327    stream.println ("  public static String id ()");
328    stream.println ("  {");
329    stream.println ("    return _id;");
330    stream.println ("  }");
331    stream.println ();
332  } // writeID
333
334  /**
335   * Generate the read method.
336   **/
337  protected void writeRead ()
338  {
339
340    boolean isLocalInterface = false;
341
342    if (entry instanceof InterfaceEntry) {
343        InterfaceEntry ie = (InterfaceEntry) entry;
344
345        // for #pragma sun_local or sun_localservant, or actual local
346        // local interface, set the flag by checking on both
347        isLocalInterface = ie.isLocal() | ie.isLocalServant();
348    }
349
350    stream.println ("  public static " + helperType + " read (org.omg.CORBA.portable.InputStream istream)");
351    stream.println ("  {");
352    if ( !isLocalInterface ) { // nonLocal Interface and other types
353      ((JavaGenerator)entry.generator ()).helperRead (helperType, entry, stream);
354    } else { //Local interface should throw exception
355      stream.println ("      throw new org.omg.CORBA.MARSHAL ();");
356    }
357    stream.println ("  }");
358    stream.println ();
359  } // writeRead
360
361  /**
362   * Generate the write method.
363   **/
364  protected void writeWrite ()
365  {
366
367    boolean isLocalInterface = false;
368
369    if (entry instanceof InterfaceEntry) {
370        InterfaceEntry ie = (InterfaceEntry) entry;
371
372        // for #pragma sun_local or sun_localservant, or actual local
373        // local interface, set the flag by checking on both
374        isLocalInterface = ie.isLocal() | ie.isLocalServant();
375    }
376
377    stream.println ("  public static void write (org.omg.CORBA.portable.OutputStream ostream, " + helperType + " value)");
378    stream.println ("  {");
379    if ( !isLocalInterface ) { // nonLocal Interface and other types
380      ((JavaGenerator)entry.generator ()).helperWrite (entry, stream);
381    } else { //Local interface should throw exception
382      stream.println ("      throw new org.omg.CORBA.MARSHAL ();");
383    }
384    stream.println ("  }");
385    stream.println ();
386  } // writeWrite
387
388
389  /**
390   * Generate the narrow method.
391   **/
392  protected void writeNarrow ()
393  {
394    writeRemoteNarrow ();
395    stream.println ();
396  }
397
398  /**
399   * Write the narrow() method for a remotable object.
400   **/
401  protected void writeRemoteNarrow ()
402  {
403    InterfaceEntry ie = (InterfaceEntry) entry;
404
405    // narrow for LocalObject interface
406    if (ie.isLocal ()) {
407        writeRemoteNarrowForLocal (false);
408        return;
409    }
410
411    // narrow for Abstract interface
412    if (ie.isAbstract ()) {
413        writeRemoteNarrowForAbstract (false);
414        return;
415    } else {
416        // Determine if the non-abstract interface has any abstract parents
417        for (int i = 0; i < ie.derivedFrom ().size (); i++) {
418            SymtabEntry parent = (SymtabEntry) ie.derivedFrom ().elementAt (i);
419            if (((InterfaceEntry) parent).isAbstract ()) {
420                writeRemoteNarrowForAbstract (true);
421                break;
422            }
423        }
424    }
425
426    stream.println ("  public static " + helperType + " narrow (org.omg.CORBA.Object obj)");
427    stream.println ("  {");
428    stream.println ("    if (obj == null)");
429    stream.println ("      return null;");
430    stream.println ("    else if (obj instanceof " + helperType + ')');
431    stream.println ("      return (" + helperType + ")obj;");
432    stream.println ("    else if (!obj._is_a (id ()))");
433    stream.println ("      throw new org.omg.CORBA.BAD_PARAM ();");
434    stream.println ("    else");
435    stream.println ("    {");
436    stream.println ("      org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();");
437    String stubNameofEntry = stubName ((InterfaceEntry)entry);
438    stream.println ("      " + stubNameofEntry + " stub = new " + stubNameofEntry + " ();");
439    stream.println ("      stub._set_delegate(delegate);");
440    stream.println ("      return stub;");
441    stream.println ("    }");
442    stream.println ("  }");
443  } // writeRemoteNarrow
444
445  /**
446   * Write the narrow() method for local interface.
447   **/
448  private void writeRemoteNarrowForLocal (boolean hasAbstractParent)
449  {
450    stream.println ("  public static " + helperType + " narrow (org.omg.CORBA.Object obj)");
451    stream.println ("  {");
452    stream.println ("    if (obj == null)");
453    stream.println ("      return null;");
454    stream.println ("    else if (obj instanceof " + helperType + ')');
455    stream.println ("      return (" + helperType + ")obj;");
456    stream.println ("    else");
457    stream.println ("      throw new org.omg.CORBA.BAD_PARAM ();");
458    stream.println ("  }");
459  } // writeRemoteNarrowForLocal
460
461  /**
462   * Write the narrow() method for abstract interface.
463   **/
464  private void writeRemoteNarrowForAbstract (boolean hasAbstractParent)
465  {
466    stream.print ("  public static " + helperType + " narrow (java.lang.Object obj)");
467    stream.println ("  {");
468    stream.println ("    if (obj == null)");
469    stream.println ("      return null;");
470    if (hasAbstractParent)
471    {
472      stream.println ("    else if (obj instanceof org.omg.CORBA.Object)");
473      stream.println ("      return narrow ((org.omg.CORBA.Object) obj);");
474    }
475    else
476    {
477      stream.println ("    else if (obj instanceof " + helperType + ')');
478      stream.println ("      return (" + helperType + ")obj;");
479    }
480
481    // If hasAbstractParent is false, then THIS entry must be abstract.
482    // This method is also called in case THIS entry is not abstract, but
483    // there is an abstract parent.  If this entry is not abstract,
484    // it can never narrow to a CORBA object reference.
485    if (!hasAbstractParent) { // <d58889>
486      String stubNameofEntry = stubName ((InterfaceEntry)entry);
487
488      stream.println ("    else if ((obj instanceof org.omg.CORBA.portable.ObjectImpl) &&");
489      stream.println ("             (((org.omg.CORBA.Object)obj)._is_a (id ()))) {");
490      stream.println ("      org.omg.CORBA.portable.ObjectImpl impl = (org.omg.CORBA.portable.ObjectImpl)obj ;" ) ;
491      stream.println ("      org.omg.CORBA.portable.Delegate delegate = impl._get_delegate() ;" ) ;
492      stream.println ("      " + stubNameofEntry + " stub = new " + stubNameofEntry + " ();");
493      stream.println ("      stub._set_delegate(delegate);");
494      stream.println ("      return stub;" ) ;
495      stream.println ("    }" ) ;
496    };
497    // end <d57118 - check for remotable - klr>
498
499    stream.println ("    throw new org.omg.CORBA.BAD_PARAM ();");
500    stream.println ("  }");
501    stream.println ();
502  } // writeRemoteNarrowForAbstract
503
504
505  /**
506   * Generate the unchecked narrow method.
507   **/
508  protected void writeUncheckedNarrow ()
509  {
510    writeUncheckedRemoteNarrow ();
511    stream.println ();
512  }
513
514  /**
515   * Write the unchecked narrow() method for a remotable object.
516   **/
517  protected void writeUncheckedRemoteNarrow ()
518  {
519    InterfaceEntry ie = (InterfaceEntry) entry;
520
521    // unchecked narrow for LocalObject interface
522    if (ie.isLocal ()) {
523        writeRemoteUncheckedNarrowForLocal (false);
524        return;
525    }
526
527    // unchecked narrow for Abstract interface
528    if (ie.isAbstract ()) {
529        writeRemoteUncheckedNarrowForAbstract (false);
530        return;
531    } else {
532        // Determine if the non-abstract interface has any abstract parents
533        for (int i = 0; i < ie.derivedFrom ().size (); i++) {
534            SymtabEntry parent = (SymtabEntry) ie.derivedFrom ().elementAt (i);
535            if (((InterfaceEntry) parent).isAbstract ()) {
536                writeRemoteUncheckedNarrowForAbstract (true);
537                break;
538            }
539        }
540    }
541
542    stream.println ("  public static " + helperType + " unchecked_narrow (org.omg.CORBA.Object obj)");
543    stream.println ("  {");
544    stream.println ("    if (obj == null)");
545    stream.println ("      return null;");
546    stream.println ("    else if (obj instanceof " + helperType + ')');
547    stream.println ("      return (" + helperType + ")obj;");
548    stream.println ("    else");
549    stream.println ("    {");
550    stream.println ("      org.omg.CORBA.portable.Delegate delegate = ((org.omg.CORBA.portable.ObjectImpl)obj)._get_delegate ();");
551    String stubNameofEntry = stubName ((InterfaceEntry)entry);
552    stream.println ("      " + stubNameofEntry + " stub = new " + stubNameofEntry + " ();");
553    stream.println ("      stub._set_delegate(delegate);");
554    stream.println ("      return stub;");
555    stream.println ("    }");
556    stream.println ("  }");
557  } // writeUncheckedRemoteNarrow
558
559  /**
560   * Write the unchecked narrow() method for local interface.
561   **/
562  private void writeRemoteUncheckedNarrowForLocal (boolean hasAbstractParent)
563  {
564    stream.println ("  public static " + helperType + " unchecked_narrow (org.omg.CORBA.Object obj)");
565    stream.println ("  {");
566    stream.println ("    if (obj == null)");
567    stream.println ("      return null;");
568    stream.println ("    else if (obj instanceof " + helperType + ')');
569    stream.println ("      return (" + helperType + ")obj;");
570    stream.println ("    else");
571    stream.println ("      throw new org.omg.CORBA.BAD_PARAM ();");
572    stream.println ("  }");
573  } // writeRemoteUncheckedNarrowForLocal
574
575  /**
576   * Write the unchecked narrow() method for abstract interface.
577   **/
578  private void writeRemoteUncheckedNarrowForAbstract (boolean hasAbstractParent)
579  {
580    stream.print ("  public static " + helperType + " unchecked_narrow (java.lang.Object obj)");
581    stream.println ("  {");
582    stream.println ("    if (obj == null)");
583    stream.println ("      return null;");
584    if (hasAbstractParent)
585    {
586      stream.println ("    else if (obj instanceof org.omg.CORBA.Object)");
587      stream.println ("      return unchecked_narrow ((org.omg.CORBA.Object) obj);");
588    }
589    else
590    {
591      stream.println ("    else if (obj instanceof " + helperType + ')');
592      stream.println ("      return (" + helperType + ")obj;");
593    }
594
595    if (!hasAbstractParent) {
596      String stubNameofEntry = stubName ((InterfaceEntry)entry);
597
598      stream.println ("    else if (obj instanceof org.omg.CORBA.portable.ObjectImpl) {");
599      stream.println ("      org.omg.CORBA.portable.ObjectImpl impl = (org.omg.CORBA.portable.ObjectImpl)obj ;" ) ;
600      stream.println ("      org.omg.CORBA.portable.Delegate delegate = impl._get_delegate() ;" ) ;
601      stream.println ("      " + stubNameofEntry + " stub = new " + stubNameofEntry + " ();");
602      stream.println ("      stub._set_delegate(delegate);");
603      stream.println ("      return stub;" ) ;
604      stream.println ("    }" ) ;
605    };
606
607    stream.println ("    throw new org.omg.CORBA.BAD_PARAM ();");
608    stream.println ("  }");
609    stream.println ();
610  } // writeRemoteUncheckedNarrowForAbstract
611
612
613  /**
614   * Generate the GetID method.
615   **/
616  protected void writeGetID ()
617  {
618    if ( !Util.IDLEntity (entry))
619      return;
620    stream.println ("  public String get_id ()");
621    stream.println ("  {");
622    stream.println ("    return _id;");
623    stream.println ("  }");
624    stream.println ();
625  } // writeGetID
626
627  /**
628   * Generate the GetType method.
629   **/
630  protected void writeGetType ()
631  {
632    if ( !Util.IDLEntity (entry))
633      return;
634    stream.println ("  public org.omg.CORBA.TypeCode get_type ()");
635    stream.println ("  {");
636    stream.println ("    return type ();");
637    stream.println ("  }");
638    stream.println ();
639  } // writeGetID
640
641  /**
642   * Generate the get_class method.
643   **/
644  protected void writeGetClass ()
645  {
646    stream.println ("  public Class get_class ()");
647    stream.println ("  {");
648    stream.println ("    return " + helperType + ".class;"); //<d59383>
649    stream.println ("  }");
650    stream.println ();
651  } // writeGetClass
652
653  /**
654   * Generate the get_instance method.
655   **/
656  protected void writeGetInstance ()
657  {
658    stream.println ("  public static org.omg.CORBA.portable.ValueHelper get_instance ()");
659    stream.println ("  {");
660    stream.println ("    return helper;");
661    stream.println ("  }");
662    stream.println ();
663  } // writeGetInstance
664
665  /**
666   * Generate the GetSafeBaseIds method.
667   **/
668  protected void writeGetSafeBaseIds ()
669  {
670    stream.println ("  public String[] get_truncatable_base_ids ()");
671    stream.println ("  {");
672    stream.println ("    return _truncatable_ids;");
673    stream.println ("  }");
674    stream.println ();
675  } // writeGetSafeBaseIds
676
677  /**
678   * Return the stub name for the interface entry.
679   **/
680  protected String stubName (InterfaceEntry entry)
681  {
682    String name;
683    if (entry.container ().name ().equals (""))
684      name =  '_' + entry.name () + "Stub";
685    else
686    {
687      name = Util.containerFullName (entry.container ()) + "._" + entry.name () + "Stub";
688    }
689    return name.replace ('/', '.');
690  } // stubName
691
692  protected java.util.Hashtable     symbolTable;
693  protected com.sun.tools.corba.se.idl.SymtabEntry entry;
694  protected GenFileStream           stream;
695
696  // Unique to this generator
697  protected String helperClass;
698  protected String helperType;
699} // class Helper
700