001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package org.apache.hadoop.record.compiler;
020    
021    import java.io.File;
022    import java.io.FileWriter;
023    import java.io.IOException;
024    import java.util.*;
025    
026    import org.apache.hadoop.classification.InterfaceAudience;
027    import org.apache.hadoop.classification.InterfaceStability;
028    
029    /**
030     * @deprecated Replaced by <a href="http://hadoop.apache.org/avro/">Avro</a>.
031     */
032    @Deprecated
033    @InterfaceAudience.Public
034    @InterfaceStability.Stable
035    public class JRecord extends JCompType {
036      
037      class JavaRecord extends JavaCompType {
038        
039        private String fullName;
040        private String name;
041        private String module;
042        private ArrayList<JField<JavaType>> fields =
043          new ArrayList<JField<JavaType>>();
044        
045        JavaRecord(String name, ArrayList<JField<JType>> flist) {
046          super(name, "Record", name, "TypeID.RIOType.STRUCT");
047          this.fullName = name;
048          int idx = name.lastIndexOf('.');
049          this.name = name.substring(idx+1);
050          this.module = name.substring(0, idx);
051          for (Iterator<JField<JType>> iter = flist.iterator(); iter.hasNext();) {
052            JField<JType> f = iter.next();
053            fields.add(new JField<JavaType>(f.getName(), f.getType().getJavaType()));
054          }
055        }
056        
057        String getTypeIDObjectString() {
058          return "new org.apache.hadoop.record.meta.StructTypeID(" + 
059          fullName + ".getTypeInfo())";
060        }
061    
062        void genSetRTIFilter(CodeBuffer cb, Map<String, Integer> nestedStructMap) {
063          // ignore, if we'ev already set the type filter for this record
064          if (!nestedStructMap.containsKey(fullName)) {
065            // we set the RTI filter here
066            cb.append(fullName + ".setTypeFilter(rti.getNestedStructTypeInfo(\""+
067                name + "\"));\n");
068            nestedStructMap.put(fullName, null);
069          }
070        }
071    
072        // for each typeInfo in the filter, we see if there's a similar one in the record. 
073        // Since we store typeInfos in ArrayLists, thsi search is O(n squared). We do it faster
074        // if we also store a map (of TypeInfo to index), but since setupRtiFields() is called
075        // only once when deserializing, we're sticking with the former, as the code is easier.  
076        void genSetupRtiFields(CodeBuffer cb) {
077          cb.append("private static void setupRtiFields()\n{\n");
078          cb.append("if (null == " + Consts.RTI_FILTER + ") return;\n");
079          cb.append("// we may already have done this\n");
080          cb.append("if (null != " + Consts.RTI_FILTER_FIELDS + ") return;\n");
081          cb.append("int " + Consts.RIO_PREFIX + "i, " + Consts.RIO_PREFIX + "j;\n");
082          cb.append(Consts.RTI_FILTER_FIELDS + " = new int [" + 
083              Consts.RIO_PREFIX + "rtiFilter.getFieldTypeInfos().size()];\n");
084          cb.append("for (" + Consts.RIO_PREFIX + "i=0; " + Consts.RIO_PREFIX + "i<"+
085              Consts.RTI_FILTER_FIELDS + ".length; " + Consts.RIO_PREFIX + "i++) {\n");
086          cb.append(Consts.RTI_FILTER_FIELDS + "[" + Consts.RIO_PREFIX + "i] = 0;\n");
087          cb.append("}\n");
088          cb.append("java.util.Iterator<org.apache.hadoop.record.meta." +
089              "FieldTypeInfo> " + Consts.RIO_PREFIX + "itFilter = " + 
090              Consts.RIO_PREFIX + "rtiFilter.getFieldTypeInfos().iterator();\n");
091          cb.append(Consts.RIO_PREFIX + "i=0;\n");
092          cb.append("while (" + Consts.RIO_PREFIX + "itFilter.hasNext()) {\n");
093          cb.append("org.apache.hadoop.record.meta.FieldTypeInfo " + 
094              Consts.RIO_PREFIX + "tInfoFilter = " + 
095              Consts.RIO_PREFIX + "itFilter.next();\n");
096          cb.append("java.util.Iterator<org.apache.hadoop.record.meta." + 
097              "FieldTypeInfo> " + Consts.RIO_PREFIX + "it = " + Consts.RTI_VAR + 
098              ".getFieldTypeInfos().iterator();\n");
099          cb.append(Consts.RIO_PREFIX + "j=1;\n");
100          cb.append("while (" + Consts.RIO_PREFIX + "it.hasNext()) {\n");
101          cb.append("org.apache.hadoop.record.meta.FieldTypeInfo " + 
102              Consts.RIO_PREFIX + "tInfo = " + Consts.RIO_PREFIX + "it.next();\n");
103          cb.append("if (" + Consts.RIO_PREFIX + "tInfo.equals(" +  
104              Consts.RIO_PREFIX + "tInfoFilter)) {\n");
105          cb.append(Consts.RTI_FILTER_FIELDS + "[" + Consts.RIO_PREFIX + "i] = " +
106              Consts.RIO_PREFIX + "j;\n");
107          cb.append("break;\n");
108          cb.append("}\n");
109          cb.append(Consts.RIO_PREFIX + "j++;\n");
110          cb.append("}\n");
111          /*int ct = 0;
112          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
113            ct++;
114            JField<JavaType> jf = i.next();
115            JavaType type = jf.getType();
116            String name = jf.getName();
117            if (ct != 1) {
118              cb.append("else ");
119            }
120            type.genRtiFieldCondition(cb, name, ct);
121          }
122          if (ct != 0) {
123            cb.append("else {\n");
124            cb.append("rtiFilterFields[i] = 0;\n");
125            cb.append("}\n");
126          }*/
127          cb.append(Consts.RIO_PREFIX + "i++;\n");
128          cb.append("}\n");
129          cb.append("}\n");
130        }
131    
132        void genReadMethod(CodeBuffer cb, String fname, String tag, boolean decl) {
133          if (decl) {
134            cb.append(fullName+" "+fname+";\n");
135          }
136          cb.append(fname+"= new "+fullName+"();\n");
137          cb.append(fname+".deserialize(" + Consts.RECORD_INPUT + ",\""+tag+"\");\n");
138        }
139        
140        void genWriteMethod(CodeBuffer cb, String fname, String tag) {
141          cb.append(fname+".serialize(" + Consts.RECORD_OUTPUT + ",\""+tag+"\");\n");
142        }
143        
144        void genSlurpBytes(CodeBuffer cb, String b, String s, String l) {
145          cb.append("{\n");
146          cb.append("int r = "+fullName+
147                    ".Comparator.slurpRaw("+b+","+s+","+l+");\n");
148          cb.append(s+"+=r; "+l+"-=r;\n");
149          cb.append("}\n");
150        }
151        
152        void genCompareBytes(CodeBuffer cb) {
153          cb.append("{\n");
154          cb.append("int r1 = "+fullName+
155                    ".Comparator.compareRaw(b1,s1,l1,b2,s2,l2);\n");
156          cb.append("if (r1 <= 0) { return r1; }\n");
157          cb.append("s1+=r1; s2+=r1; l1-=r1; l2-=r1;\n");
158          cb.append("}\n");
159        }
160        
161        void genCode(String destDir, ArrayList<String> options) throws IOException {
162          String pkg = module;
163          String pkgpath = pkg.replaceAll("\\.", "/");
164          File pkgdir = new File(destDir, pkgpath);
165    
166          final File jfile = new File(pkgdir, name+".java");
167          if (!pkgdir.exists()) {
168            // create the pkg directory
169            boolean ret = pkgdir.mkdirs();
170            if (!ret) {
171              throw new IOException("Cannnot create directory: "+pkgpath);
172            }
173          } else if (!pkgdir.isDirectory()) {
174            // not a directory
175            throw new IOException(pkgpath+" is not a directory.");
176          }
177    
178          CodeBuffer cb = new CodeBuffer();
179          cb.append("// File generated by hadoop record compiler. Do not edit.\n");
180          cb.append("package "+module+";\n\n");
181          cb.append("public class "+name+
182                    " extends org.apache.hadoop.record.Record {\n");
183          
184          // type information declarations
185          cb.append("private static final " + 
186              "org.apache.hadoop.record.meta.RecordTypeInfo " + 
187              Consts.RTI_VAR + ";\n");
188          cb.append("private static " + 
189              "org.apache.hadoop.record.meta.RecordTypeInfo " + 
190              Consts.RTI_FILTER + ";\n");
191          cb.append("private static int[] " + Consts.RTI_FILTER_FIELDS + ";\n");
192          
193          // static init for type information
194          cb.append("static {\n");
195          cb.append(Consts.RTI_VAR + " = " +
196              "new org.apache.hadoop.record.meta.RecordTypeInfo(\"" +
197              name + "\");\n");
198          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
199            JField<JavaType> jf = i.next();
200            String name = jf.getName();
201            JavaType type = jf.getType();
202            type.genStaticTypeInfo(cb, name);
203          }
204          cb.append("}\n\n");
205    
206          // field definitions
207          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
208            JField<JavaType> jf = i.next();
209            String name = jf.getName();
210            JavaType type = jf.getType();
211            type.genDecl(cb, name);
212          }
213    
214          // default constructor
215          cb.append("public "+name+"() { }\n");
216          
217          // constructor
218          cb.append("public "+name+"(\n");
219          int fIdx = 0;
220          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext(); fIdx++) {
221            JField<JavaType> jf = i.next();
222            String name = jf.getName();
223            JavaType type = jf.getType();
224            type.genConstructorParam(cb, name);
225            cb.append((!i.hasNext())?"":",\n");
226          }
227          cb.append(") {\n");
228          fIdx = 0;
229          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext(); fIdx++) {
230            JField<JavaType> jf = i.next();
231            String name = jf.getName();
232            JavaType type = jf.getType();
233            type.genConstructorSet(cb, name);
234          }
235          cb.append("}\n");
236    
237          // getter/setter for type info
238          cb.append("public static org.apache.hadoop.record.meta.RecordTypeInfo"
239                  + " getTypeInfo() {\n");
240          cb.append("return " + Consts.RTI_VAR + ";\n");
241          cb.append("}\n");
242          cb.append("public static void setTypeFilter("
243              + "org.apache.hadoop.record.meta.RecordTypeInfo rti) {\n");
244          cb.append("if (null == rti) return;\n");
245          cb.append(Consts.RTI_FILTER + " = rti;\n");
246          cb.append(Consts.RTI_FILTER_FIELDS + " = null;\n");
247          // set RTIFilter for nested structs.
248          // To prevent setting up the type filter for the same struct more than once, 
249          // we use a hash map to keep track of what we've set. 
250          Map<String, Integer> nestedStructMap = new HashMap<String, Integer>();
251          for (JField<JavaType> jf : fields) {
252            JavaType type = jf.getType();
253            type.genSetRTIFilter(cb, nestedStructMap);
254          }
255          cb.append("}\n");
256    
257          // setupRtiFields()
258          genSetupRtiFields(cb);
259    
260          // getters/setters for member variables
261          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
262            JField<JavaType> jf = i.next();
263            String name = jf.getName();
264            JavaType type = jf.getType();
265            type.genGetSet(cb, name);
266          }
267          
268          // serialize()
269          cb.append("public void serialize("+ 
270              "final org.apache.hadoop.record.RecordOutput " + 
271              Consts.RECORD_OUTPUT + ", final String " + Consts.TAG + ")\n"+
272                    "throws java.io.IOException {\n");
273          cb.append(Consts.RECORD_OUTPUT + ".startRecord(this," + Consts.TAG + ");\n");
274          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
275            JField<JavaType> jf = i.next();
276            String name = jf.getName();
277            JavaType type = jf.getType();
278            type.genWriteMethod(cb, name, name);
279          }
280          cb.append(Consts.RECORD_OUTPUT + ".endRecord(this," + Consts.TAG+");\n");
281          cb.append("}\n");
282    
283          // deserializeWithoutFilter()
284          cb.append("private void deserializeWithoutFilter("+
285                    "final org.apache.hadoop.record.RecordInput " + 
286                    Consts.RECORD_INPUT + ", final String " + Consts.TAG + ")\n"+
287                    "throws java.io.IOException {\n");
288          cb.append(Consts.RECORD_INPUT + ".startRecord(" + Consts.TAG + ");\n");
289          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
290            JField<JavaType> jf = i.next();
291            String name = jf.getName();
292            JavaType type = jf.getType();
293            type.genReadMethod(cb, name, name, false);
294          }
295          cb.append(Consts.RECORD_INPUT + ".endRecord(" + Consts.TAG+");\n");
296          cb.append("}\n");
297          
298          // deserialize()
299          cb.append("public void deserialize(final " +
300              "org.apache.hadoop.record.RecordInput " + 
301              Consts.RECORD_INPUT + ", final String " + Consts.TAG + ")\n"+
302              "throws java.io.IOException {\n");
303          cb.append("if (null == " + Consts.RTI_FILTER + ") {\n");
304          cb.append("deserializeWithoutFilter(" + Consts.RECORD_INPUT + ", " + 
305              Consts.TAG + ");\n");
306          cb.append("return;\n");
307          cb.append("}\n");
308          cb.append("// if we're here, we need to read based on version info\n");
309          cb.append(Consts.RECORD_INPUT + ".startRecord(" + Consts.TAG + ");\n");
310          cb.append("setupRtiFields();\n");
311          cb.append("for (int " + Consts.RIO_PREFIX + "i=0; " + Consts.RIO_PREFIX + 
312              "i<" + Consts.RTI_FILTER + ".getFieldTypeInfos().size(); " + 
313              Consts.RIO_PREFIX + "i++) {\n");
314          int ct = 0;
315          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
316            JField<JavaType> jf = i.next();
317            String name = jf.getName();
318            JavaType type = jf.getType();
319            ct++;
320            if (1 != ct) {
321              cb.append("else ");
322            }
323            cb.append("if (" + ct + " == " + Consts.RTI_FILTER_FIELDS + "[" +
324                Consts.RIO_PREFIX + "i]) {\n");
325            type.genReadMethod(cb, name, name, false);
326            cb.append("}\n");
327          }
328          if (0 != ct) {
329            cb.append("else {\n");
330            cb.append("java.util.ArrayList<"
331                    + "org.apache.hadoop.record.meta.FieldTypeInfo> typeInfos = "
332                    + "(java.util.ArrayList<"
333                    + "org.apache.hadoop.record.meta.FieldTypeInfo>)"
334                    + "(" + Consts.RTI_FILTER + ".getFieldTypeInfos());\n");
335            cb.append("org.apache.hadoop.record.meta.Utils.skip(" + 
336                Consts.RECORD_INPUT + ", " + "typeInfos.get(" + Consts.RIO_PREFIX + 
337                "i).getFieldID(), typeInfos.get(" + 
338                Consts.RIO_PREFIX + "i).getTypeID());\n");
339            cb.append("}\n");
340          }
341          cb.append("}\n");
342          cb.append(Consts.RECORD_INPUT + ".endRecord(" + Consts.TAG+");\n");
343          cb.append("}\n");
344    
345          // compareTo()
346          cb.append("public int compareTo (final Object " + Consts.RIO_PREFIX + 
347              "peer_) throws ClassCastException {\n");
348          cb.append("if (!(" + Consts.RIO_PREFIX + "peer_ instanceof "+name+")) {\n");
349          cb.append("throw new ClassCastException(\"Comparing different types of records.\");\n");
350          cb.append("}\n");
351          cb.append(name+" " + Consts.RIO_PREFIX + "peer = ("+name+") " + 
352              Consts.RIO_PREFIX + "peer_;\n");
353          cb.append("int " + Consts.RIO_PREFIX + "ret = 0;\n");
354          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
355            JField<JavaType> jf = i.next();
356            String name = jf.getName();
357            JavaType type = jf.getType();
358            type.genCompareTo(cb, name, Consts.RIO_PREFIX + "peer."+name);
359            cb.append("if (" + Consts.RIO_PREFIX + "ret != 0) return " + 
360                Consts.RIO_PREFIX + "ret;\n");
361          }
362          cb.append("return " + Consts.RIO_PREFIX + "ret;\n");
363          cb.append("}\n");
364          
365          // equals()
366          cb.append("public boolean equals(final Object " + Consts.RIO_PREFIX + 
367              "peer_) {\n");
368          cb.append("if (!(" + Consts.RIO_PREFIX + "peer_ instanceof "+name+")) {\n");
369          cb.append("return false;\n");
370          cb.append("}\n");
371          cb.append("if (" + Consts.RIO_PREFIX + "peer_ == this) {\n");
372          cb.append("return true;\n");
373          cb.append("}\n");
374          cb.append(name+" " + Consts.RIO_PREFIX + "peer = ("+name+") " + 
375              Consts.RIO_PREFIX + "peer_;\n");
376          cb.append("boolean " + Consts.RIO_PREFIX + "ret = false;\n");
377          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
378            JField<JavaType> jf = i.next();
379            String name = jf.getName();
380            JavaType type = jf.getType();
381            type.genEquals(cb, name, Consts.RIO_PREFIX + "peer."+name);
382            cb.append("if (!" + Consts.RIO_PREFIX + "ret) return " + 
383                Consts.RIO_PREFIX + "ret;\n");
384          }
385          cb.append("return " + Consts.RIO_PREFIX + "ret;\n");
386          cb.append("}\n");
387    
388          // clone()
389          cb.append("public Object clone() throws CloneNotSupportedException {\n");
390          cb.append(name+" " + Consts.RIO_PREFIX + "other = new "+name+"();\n");
391          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
392            JField<JavaType> jf = i.next();
393            String name = jf.getName();
394            JavaType type = jf.getType();
395            type.genClone(cb, name);
396          }
397          cb.append("return " + Consts.RIO_PREFIX + "other;\n");
398          cb.append("}\n");
399          
400          cb.append("public int hashCode() {\n");
401          cb.append("int " + Consts.RIO_PREFIX + "result = 17;\n");
402          cb.append("int " + Consts.RIO_PREFIX + "ret;\n");
403          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
404            JField<JavaType> jf = i.next();
405            String name = jf.getName();
406            JavaType type = jf.getType();
407            type.genHashCode(cb, name);
408            cb.append(Consts.RIO_PREFIX + "result = 37*" + Consts.RIO_PREFIX + 
409                "result + " + Consts.RIO_PREFIX + "ret;\n");
410          }
411          cb.append("return " + Consts.RIO_PREFIX + "result;\n");
412          cb.append("}\n");
413          
414          cb.append("public static String signature() {\n");
415          cb.append("return \""+getSignature()+"\";\n");
416          cb.append("}\n");
417          
418          cb.append("public static class Comparator extends"+
419                    " org.apache.hadoop.record.RecordComparator {\n");
420          cb.append("public Comparator() {\n");
421          cb.append("super("+name+".class);\n");
422          cb.append("}\n");
423          
424          cb.append("static public int slurpRaw(byte[] b, int s, int l) {\n");
425          cb.append("try {\n");
426          cb.append("int os = s;\n");
427          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
428            JField<JavaType> jf = i.next();
429            String name = jf.getName();
430            JavaType type = jf.getType();
431            type.genSlurpBytes(cb, "b","s","l");
432          }
433          cb.append("return (os - s);\n");
434          cb.append("} catch(java.io.IOException e) {\n");
435          cb.append("throw new RuntimeException(e);\n");
436          cb.append("}\n");
437          cb.append("}\n");
438          
439          cb.append("static public int compareRaw(byte[] b1, int s1, int l1,\n");
440          cb.append("                             byte[] b2, int s2, int l2) {\n");
441          cb.append("try {\n");
442          cb.append("int os1 = s1;\n");
443          for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) {
444            JField<JavaType> jf = i.next();
445            String name = jf.getName();
446            JavaType type = jf.getType();
447            type.genCompareBytes(cb);
448          }
449          cb.append("return (os1 - s1);\n");
450          cb.append("} catch(java.io.IOException e) {\n");
451          cb.append("throw new RuntimeException(e);\n");
452          cb.append("}\n");
453          cb.append("}\n");
454          cb.append("public int compare(byte[] b1, int s1, int l1,\n");
455          cb.append("                   byte[] b2, int s2, int l2) {\n");
456          cb.append("int ret = compareRaw(b1,s1,l1,b2,s2,l2);\n");
457          cb.append("return (ret == -1)? -1 : ((ret==0)? 1 : 0);");
458          cb.append("}\n");
459          cb.append("}\n\n");
460          cb.append("static {\n");
461          cb.append("org.apache.hadoop.record.RecordComparator.define("
462                    +name+".class, new Comparator());\n");
463          cb.append("}\n");
464          cb.append("}\n");
465    
466          FileWriter jj = new FileWriter(jfile);
467          try {
468            jj.write(cb.toString());
469          } finally {
470            jj.close();
471          }
472        }
473      }
474      
475      class CppRecord extends CppCompType {
476        
477        private String fullName;
478        private String name;
479        private String module;
480        private ArrayList<JField<CppType>> fields = 
481          new ArrayList<JField<CppType>>();
482        
483        CppRecord(String name, ArrayList<JField<JType>> flist) {
484          super(name.replaceAll("\\.","::"));
485          this.fullName = name.replaceAll("\\.", "::");
486          int idx = name.lastIndexOf('.');
487          this.name = name.substring(idx+1);
488          this.module = name.substring(0, idx).replaceAll("\\.", "::");
489          for (Iterator<JField<JType>> iter = flist.iterator(); iter.hasNext();) {
490            JField<JType> f = iter.next();
491            fields.add(new JField<CppType>(f.getName(), f.getType().getCppType()));
492          }
493        }
494        
495        String getTypeIDObjectString() {
496          return "new ::hadoop::StructTypeID(" + 
497          fullName + "::getTypeInfo().getFieldTypeInfos())";
498        }
499    
500        String genDecl(String fname) {
501          return "  "+name+" "+fname+";\n";
502        }
503        
504        void genSetRTIFilter(CodeBuffer cb) {
505          // we set the RTI filter here
506          cb.append(fullName + "::setTypeFilter(rti.getNestedStructTypeInfo(\""+
507              name + "\"));\n");
508        }
509    
510        void genSetupRTIFields(CodeBuffer cb) {
511          cb.append("void " + fullName + "::setupRtiFields() {\n");
512          cb.append("if (NULL == p" + Consts.RTI_FILTER + ") return;\n");
513          cb.append("if (NULL != p" + Consts.RTI_FILTER_FIELDS + ") return;\n");
514          cb.append("p" + Consts.RTI_FILTER_FIELDS + " = new int[p" + 
515              Consts.RTI_FILTER + "->getFieldTypeInfos().size()];\n");
516          cb.append("for (unsigned int " + Consts.RIO_PREFIX + "i=0; " + 
517              Consts.RIO_PREFIX + "i<p" + Consts.RTI_FILTER + 
518              "->getFieldTypeInfos().size(); " + Consts.RIO_PREFIX + "i++) {\n");
519          cb.append("p" + Consts.RTI_FILTER_FIELDS + "[" + Consts.RIO_PREFIX + 
520              "i] = 0;\n");
521          cb.append("}\n");
522          cb.append("for (unsigned int " + Consts.RIO_PREFIX + "i=0; " + 
523              Consts.RIO_PREFIX + "i<p" + Consts.RTI_FILTER + 
524              "->getFieldTypeInfos().size(); " + Consts.RIO_PREFIX + "i++) {\n");
525          cb.append("for (unsigned int " + Consts.RIO_PREFIX + "j=0; " + 
526              Consts.RIO_PREFIX + "j<p" + Consts.RTI_VAR + 
527              "->getFieldTypeInfos().size(); " + Consts.RIO_PREFIX + "j++) {\n");
528          cb.append("if (*(p" + Consts.RTI_FILTER + "->getFieldTypeInfos()[" + 
529              Consts.RIO_PREFIX + "i]) == *(p" + Consts.RTI_VAR + 
530              "->getFieldTypeInfos()[" + Consts.RIO_PREFIX + "j])) {\n");
531          cb.append("p" + Consts.RTI_FILTER_FIELDS + "[" + Consts.RIO_PREFIX + 
532              "i] = " + Consts.RIO_PREFIX + "j+1;\n");
533          cb.append("break;\n");
534          cb.append("}\n");
535          cb.append("}\n");
536          cb.append("}\n");
537          cb.append("}\n");
538        }
539        
540        void genCode(FileWriter hh, FileWriter cc, ArrayList<String> options)
541          throws IOException {
542          CodeBuffer hb = new CodeBuffer();
543          
544          String[] ns = module.split("::");
545          for (int i = 0; i < ns.length; i++) {
546            hb.append("namespace "+ns[i]+" {\n");
547          }
548          
549          hb.append("class "+name+" : public ::hadoop::Record {\n");
550          hb.append("private:\n");
551          
552          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
553            JField<CppType> jf = i.next();
554            String name = jf.getName();
555            CppType type = jf.getType();
556            type.genDecl(hb, name);
557          }
558          
559          // type info vars
560          hb.append("static ::hadoop::RecordTypeInfo* p" + Consts.RTI_VAR + ";\n");
561          hb.append("static ::hadoop::RecordTypeInfo* p" + Consts.RTI_FILTER + ";\n");
562          hb.append("static int* p" + Consts.RTI_FILTER_FIELDS + ";\n");
563          hb.append("static ::hadoop::RecordTypeInfo* setupTypeInfo();\n");
564          hb.append("static void setupRtiFields();\n");
565          hb.append("virtual void deserializeWithoutFilter(::hadoop::IArchive& " + 
566              Consts.RECORD_INPUT + ", const char* " + Consts.TAG + ");\n");
567          hb.append("public:\n");
568          hb.append("static const ::hadoop::RecordTypeInfo& getTypeInfo() " +
569              "{return *p" + Consts.RTI_VAR + ";}\n");
570          hb.append("static void setTypeFilter(const ::hadoop::RecordTypeInfo& rti);\n");
571          hb.append("static void setTypeFilter(const ::hadoop::RecordTypeInfo* prti);\n");
572          hb.append("virtual void serialize(::hadoop::OArchive& " + 
573              Consts.RECORD_OUTPUT + ", const char* " + Consts.TAG + ") const;\n");
574          hb.append("virtual void deserialize(::hadoop::IArchive& " + 
575              Consts.RECORD_INPUT + ", const char* " + Consts.TAG + ");\n");
576          hb.append("virtual const ::std::string& type() const;\n");
577          hb.append("virtual const ::std::string& signature() const;\n");
578          hb.append("virtual bool operator<(const "+name+"& peer_) const;\n");
579          hb.append("virtual bool operator==(const "+name+"& peer_) const;\n");
580          hb.append("virtual ~"+name+"() {};\n");
581          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
582            JField<CppType> jf = i.next();
583            String name = jf.getName();
584            CppType type = jf.getType();
585            type.genGetSet(hb, name);
586          }
587          hb.append("}; // end record "+name+"\n");
588          for (int i=ns.length-1; i>=0; i--) {
589            hb.append("} // end namespace "+ns[i]+"\n");
590          }
591          
592          hh.write(hb.toString());
593          
594          CodeBuffer cb = new CodeBuffer();
595    
596          // initialize type info vars
597          cb.append("::hadoop::RecordTypeInfo* " + fullName + "::p" + 
598              Consts.RTI_VAR + " = " + fullName + "::setupTypeInfo();\n");
599          cb.append("::hadoop::RecordTypeInfo* " + fullName + "::p" + 
600              Consts.RTI_FILTER + " = NULL;\n");
601          cb.append("int* " + fullName + "::p" + 
602              Consts.RTI_FILTER_FIELDS + " = NULL;\n\n");
603    
604          // setupTypeInfo()
605          cb.append("::hadoop::RecordTypeInfo* "+fullName+"::setupTypeInfo() {\n");
606          cb.append("::hadoop::RecordTypeInfo* p = new ::hadoop::RecordTypeInfo(\"" + 
607              name + "\");\n");
608          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
609            JField<CppType> jf = i.next();
610            String name = jf.getName();
611            CppType type = jf.getType();
612            type.genStaticTypeInfo(cb, name);
613          }
614          cb.append("return p;\n");
615          cb.append("}\n");
616    
617          // setTypeFilter()
618          cb.append("void "+fullName+"::setTypeFilter(const " +
619              "::hadoop::RecordTypeInfo& rti) {\n");
620          cb.append("if (NULL != p" + Consts.RTI_FILTER + ") {\n");
621          cb.append("delete p" + Consts.RTI_FILTER + ";\n");
622          cb.append("}\n");
623          cb.append("p" + Consts.RTI_FILTER + " = new ::hadoop::RecordTypeInfo(rti);\n");
624          cb.append("if (NULL != p" + Consts.RTI_FILTER_FIELDS + ") {\n");
625          cb.append("delete p" + Consts.RTI_FILTER_FIELDS + ";\n");
626          cb.append("}\n");
627          cb.append("p" + Consts.RTI_FILTER_FIELDS + " = NULL;\n");
628          // set RTIFilter for nested structs. We may end up with multiple lines that 
629          // do the same thing, if the same struct is nested in more than one field, 
630          // but that's OK. 
631          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
632            JField<CppType> jf = i.next();
633            CppType type = jf.getType();
634            type.genSetRTIFilter(cb);
635          }
636          cb.append("}\n");
637          
638          // setTypeFilter()
639          cb.append("void "+fullName+"::setTypeFilter(const " +
640              "::hadoop::RecordTypeInfo* prti) {\n");
641          cb.append("if (NULL != prti) {\n");
642          cb.append("setTypeFilter(*prti);\n");
643          cb.append("}\n");
644          cb.append("}\n");
645    
646          // setupRtiFields()
647          genSetupRTIFields(cb);
648    
649          // serialize()
650          cb.append("void "+fullName+"::serialize(::hadoop::OArchive& " + 
651              Consts.RECORD_OUTPUT + ", const char* " + Consts.TAG + ") const {\n");
652          cb.append(Consts.RECORD_OUTPUT + ".startRecord(*this," + 
653              Consts.TAG + ");\n");
654          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
655            JField<CppType> jf = i.next();
656            String name = jf.getName();
657            CppType type = jf.getType();
658            if (type instanceof JBuffer.CppBuffer) {
659              cb.append(Consts.RECORD_OUTPUT + ".serialize("+name+","+name+
660                  ".length(),\""+name+"\");\n");
661            } else {
662              cb.append(Consts.RECORD_OUTPUT + ".serialize("+name+",\""+
663                  name+"\");\n");
664            }
665          }
666          cb.append(Consts.RECORD_OUTPUT + ".endRecord(*this," + Consts.TAG + ");\n");
667          cb.append("return;\n");
668          cb.append("}\n");
669          
670          // deserializeWithoutFilter()
671          cb.append("void "+fullName+"::deserializeWithoutFilter(::hadoop::IArchive& " +
672              Consts.RECORD_INPUT + ", const char* " + Consts.TAG + ") {\n");
673          cb.append(Consts.RECORD_INPUT + ".startRecord(*this," + 
674              Consts.TAG + ");\n");
675          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
676            JField<CppType> jf = i.next();
677            String name = jf.getName();
678            CppType type = jf.getType();
679            if (type instanceof JBuffer.CppBuffer) {
680              cb.append("{\nsize_t len=0; " + Consts.RECORD_INPUT + ".deserialize("+
681                  name+",len,\""+name+"\");\n}\n");
682            } else {
683              cb.append(Consts.RECORD_INPUT + ".deserialize("+name+",\""+
684                  name+"\");\n");
685            }
686          }
687          cb.append(Consts.RECORD_INPUT + ".endRecord(*this," + Consts.TAG + ");\n");
688          cb.append("return;\n");
689          cb.append("}\n");
690          
691          // deserialize()
692          cb.append("void "+fullName+"::deserialize(::hadoop::IArchive& " +
693              Consts.RECORD_INPUT + ", const char* " + Consts.TAG + ") {\n");
694          cb.append("if (NULL == p" + Consts.RTI_FILTER + ") {\n");
695          cb.append("deserializeWithoutFilter(" + Consts.RECORD_INPUT + ", " + 
696              Consts.TAG + ");\n");
697          cb.append("return;\n");
698          cb.append("}\n");
699          cb.append("// if we're here, we need to read based on version info\n");
700          cb.append(Consts.RECORD_INPUT + ".startRecord(*this," + 
701              Consts.TAG + ");\n");
702          cb.append("setupRtiFields();\n");
703          cb.append("for (unsigned int " + Consts.RIO_PREFIX + "i=0; " + 
704              Consts.RIO_PREFIX + "i<p" + Consts.RTI_FILTER + 
705              "->getFieldTypeInfos().size(); " + Consts.RIO_PREFIX + "i++) {\n");
706          int ct = 0;
707          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
708            JField<CppType> jf = i.next();
709            String name = jf.getName();
710            CppType type = jf.getType();
711            ct++;
712            if (1 != ct) {
713              cb.append("else ");
714            }
715            cb.append("if (" + ct + " == p" + Consts.RTI_FILTER_FIELDS + "[" +
716                Consts.RIO_PREFIX + "i]) {\n");
717            if (type instanceof JBuffer.CppBuffer) {
718              cb.append("{\nsize_t len=0; " + Consts.RECORD_INPUT + ".deserialize("+
719                  name+",len,\""+name+"\");\n}\n");
720            } else {
721              cb.append(Consts.RECORD_INPUT + ".deserialize("+name+",\""+
722                  name+"\");\n");
723            }
724            cb.append("}\n");
725          }
726          if (0 != ct) {
727            cb.append("else {\n");
728            cb.append("const std::vector< ::hadoop::FieldTypeInfo* >& typeInfos = p" + 
729                Consts.RTI_FILTER + "->getFieldTypeInfos();\n");
730            cb.append("::hadoop::Utils::skip(" + Consts.RECORD_INPUT + 
731                ", typeInfos[" + Consts.RIO_PREFIX + "i]->getFieldID()->c_str()" + 
732                ", *(typeInfos[" + Consts.RIO_PREFIX + "i]->getTypeID()));\n");
733            cb.append("}\n");
734          }
735          cb.append("}\n");
736          cb.append(Consts.RECORD_INPUT + ".endRecord(*this, " + Consts.TAG+");\n");
737          cb.append("}\n");
738    
739          // operator <
740          cb.append("bool "+fullName+"::operator< (const "+fullName+"& peer_) const {\n");
741          cb.append("return (1\n");
742          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
743            JField<CppType> jf = i.next();
744            String name = jf.getName();
745            cb.append("&& ("+name+" < peer_."+name+")\n");
746          }
747          cb.append(");\n");
748          cb.append("}\n");
749          
750          cb.append("bool "+fullName+"::operator== (const "+fullName+"& peer_) const {\n");
751          cb.append("return (1\n");
752          for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) {
753            JField<CppType> jf = i.next();
754            String name = jf.getName();
755            cb.append("&& ("+name+" == peer_."+name+")\n");
756          }
757          cb.append(");\n");
758          cb.append("}\n");
759          
760          cb.append("const ::std::string&"+fullName+"::type() const {\n");
761          cb.append("static const ::std::string type_(\""+name+"\");\n");
762          cb.append("return type_;\n");
763          cb.append("}\n");
764          
765          cb.append("const ::std::string&"+fullName+"::signature() const {\n");
766          cb.append("static const ::std::string sig_(\""+getSignature()+"\");\n");
767          cb.append("return sig_;\n");
768          cb.append("}\n");
769          
770          cc.write(cb.toString());
771        }
772      }
773      
774      class CRecord extends CCompType {
775        
776      }
777      
778      private String signature;
779      
780      /**
781       * Creates a new instance of JRecord
782       */
783      public JRecord(String name, ArrayList<JField<JType>> flist) {
784        setJavaType(new JavaRecord(name, flist));
785        setCppType(new CppRecord(name, flist));
786        setCType(new CRecord());
787        // precompute signature
788        int idx = name.lastIndexOf('.');
789        String recName = name.substring(idx+1);
790        StringBuilder sb = new StringBuilder();
791        sb.append("L").append(recName).append("(");
792        for (Iterator<JField<JType>> i = flist.iterator(); i.hasNext();) {
793          String s = i.next().getType().getSignature();
794          sb.append(s);
795        }
796        sb.append(")");
797        signature = sb.toString();
798      }
799      
800      String getSignature() {
801        return signature;
802      }
803      
804      void genCppCode(FileWriter hh, FileWriter cc, ArrayList<String> options)
805        throws IOException {
806        ((CppRecord)getCppType()).genCode(hh, cc, options);
807      }
808      
809      void genJavaCode(String destDir, ArrayList<String> options)
810        throws IOException {
811        ((JavaRecord)getJavaType()).genCode(destDir, options);
812      }
813    }