/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.commoncrawl.rpc.compiler; import java.io.DataInput; import java.io.DataOutput; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.Vector; import java.io.StringWriter; import java.math.BigInteger; import org.commoncrawl.rpc.base.shared.BinaryProtocol; import com.google.gson.JsonObject; import com.google.gson.stream.JsonWriter; /** */ public class JRecord extends JCompType { public static class Modifiers { public static int HAS_RECORDID = 1 << 0; public static int HAS_NO_DIRTY_TRACKING = 1 << 1; public static int IS_ANONYMOUS_RECORD = 1 << 2; } class JavaRecord extends JavaCompType { private String fullName; private String name; private String module; private ArrayList<JField<JavaType>> fields = new ArrayList<JField<JavaType>>(); private ArrayList<JEnum> enums = new ArrayList<JEnum>(); private Vector < JField<JavaType> > keys = new Vector < JField<JavaType> >(); private int modifiers = 0; JavaRecord(String name, ArrayList<JField<JType>> flist,ArrayList<JEnum> enums,Set<String> modifiers) { super(name, "Record", name); this.fullName = name; int idx = name.lastIndexOf('.'); this.name = name.substring(idx+1); this.module = name.substring(0, idx); for (Iterator<JField<JType>> iter = flist.iterator(); iter.hasNext();) { JField<JType> f = iter.next(); JField<JavaType> newField = new JField<JavaType>(f.getName(), f.getType().getJavaType(),f.getOrdinal(),f.getModifiers()); fields.add(newField); if ((newField.getModifiers() & JField.Modifiers.KEY)!= 0) { if (!newField.getType().isComparable()) { throw new Error("key attribute assigned to a non Comparable Field:" + newField + " Record:" + getFullName()); } keys.add(newField); } } this.enums = enums; parseModifiers(modifiers); } @Override boolean isIntrinsicType() { return false; } private void parseModifiers(Set<String> modifierSet) { if (modifierSet != null) { for (String modifier : modifierSet) { if (modifier.equals("recordid")) { modifiers |= Modifiers.HAS_RECORDID; } else if (modifier.equals("nodirty")) { modifiers |= Modifiers.HAS_NO_DIRTY_TRACKING; } else if (modifier.equals("anonymous")) { modifiers |= Modifiers.IS_ANONYMOUS_RECORD; } else { throw new Error("Invalid Record Modifier token:" + modifier + " encountered while parsing Record:" + getFullName()); } } } } @Override boolean isComparable() { return keys.size() != 0; } private boolean trackDirtyFields() { return (modifiers & Modifiers.HAS_NO_DIRTY_TRACKING) == 0; } public String getFullName() { return fullName; } public String getShortName() { return name; } public Vector< JField<JavaType> > getKeys() { return keys; } public int getKeyCount() { return keys.size(); } @Override void genReadMethod(CodeBuffer cb, String fname, String tag, boolean decl) { if (decl) { cb.append(fullName+" "+fname+";\n"); } cb.append(fname+"= new "+fullName+"();\n"); cb.append(fname+".deserialize(input,decoder);\n"); } @Override void genSkipMethod(CodeBuffer cb) { cb.append(fullName+".skipTo(input,decoder,Integer.MAX_VALUE);\n"); } @Override void genWriteMethod(CodeBuffer cb, String fname, String tag) { cb.append(fname+".serialize(output,encoder);\n"); } void genCode(String destDir, ArrayList<String> options) throws IOException { String pkg = module; String pkgpath = pkg.replaceAll("\\.", "/"); File pkgdir = new File(destDir, pkgpath); if (!pkgdir.exists()) { // create the pkg directory boolean ret = pkgdir.mkdirs(); if (!ret) { throw new IOException("Cannnot create directory: "+pkgpath); } } else if (!pkgdir.isDirectory()) { // not a directory throw new IOException(pkgpath+" is not a directory."); } File jfile = new File(pkgdir, name+".java"); FileWriter jj = new FileWriter(jfile); CodeBuffer cb = new CodeBuffer(); cb.append("// File generated by rpc compiler. Do not edit.\n\n"); cb.append("package "+module+";\n\n"); cb.append("import org.apache.hadoop.io.DataInputBuffer;\n"); cb.append("import java.io.DataInput;\n"); cb.append("import java.io.DataOutput;\n"); cb.append("import java.util.BitSet;\n"); cb.append("import java.io.IOException;\n"); cb.append("import org.apache.hadoop.io.Writable;\n"); cb.append("import org.apache.hadoop.io.WritableComparable;\n"); cb.append("import org.apache.hadoop.record.Buffer;\n"); cb.append("import org.commoncrawl.util.FlexBuffer;\n"); cb.append("import org.commoncrawl.util.TextBytes;\n"); cb.append("import org.commoncrawl.util.MurmurHash;\n"); cb.append("import org.commoncrawl.util.ImmutableBuffer;\n"); cb.append("import org.commoncrawl.rpc.base.shared.BinaryProtocol;\n"); cb.append("import org.apache.hadoop.util.ReflectionUtils;\n"); cb.append("import org.apache.hadoop.conf.Configuration;\n"); cb.append("import java.io.StringWriter;\n"); cb.append("import com.google.gson.JsonObject;\n"); cb.append("import com.google.gson.stream.JsonWriter;\n"); cb.append("// Generated File: "+name+"\n"); cb.append("public class "+name); if ((modifiers & Modifiers.HAS_RECORDID) != 0) { cb.append(" extends org.commoncrawl.rpc.base.shared.RPCStructWithId "); } else { cb.append(" extends org.commoncrawl.rpc.base.shared.RPCStruct "); } // if the field has no key then implement Writable only if (this.getKeyCount() == 0) { cb.append(" implements Writable"); } // otherwise implement WritableComparable else { // this check has moved to initialization /* if (!this.getKey().getType().isComparable()) { throw new Error("Invalid Key Type in Record:"+this.fullName); } */ cb.append(" implements WritableComparable "); } cb.append("{\n\n"); cb.append("// optimized constructor helper \n"); cb.append("public static " + name + " newInstance(Configuration conf) {\n"); cb.append(" return ReflectionUtils.newInstance(" + name + ".class,conf);\n"); cb.append("}\n"); cb.append("// Writable Implementation\n"); cb.append("public void write(DataOutput out) throws IOException{ \n"); cb.append("this.serialize(out,new BinaryProtocol());\n"); cb.append("}\n\n"); cb.append("public void readFields(DataInput in) throws IOException{ \n"); cb.append("this.deserialize(in,new BinaryProtocol());\n"); cb.append("}\n\n"); // now if sortable filed is available ... if (this.getKeyCount() != 0) { cb.append("// Comparable Implementation\n"); cb.append("public int compareTo(Object other) {\n"); int keyCount = 0; for (JField<JavaType> field : getKeys()) { if (keyCount++ == 0) { cb.append("int result = "); } else { cb.append("if (result == 0) result = "); } cb.append(field.getType().genCompareTo(field.getName(),"other",this.getFullName()) + ";\n"); } cb.append("return result;\n"); cb.append("}\n"); cb.append("// getKey Implementation\n"); cb.append("public String getKey(){\n"); if (getKeyCount() == 1) { cb.append(" return " + this.getKeys().get(0).getType().genGetKey(getKeys().get(0).getName()) + ";\n"); } else { cb.append(" return"); keyCount = 0; for (JField<JavaType> field : getKeys()) { if (keyCount++ != 0) cb.append("+ \"_\" +"); cb.append("\"" + field.getName() + "_\"+" + field.getType().genGetKey(field.getName())); } cb.append(";\n"); } cb.append("}\n\n"); } cb.append("\n"); cb.append("// Field Constants\n"); int fieldOrdinalMax = 0; JField<JavaType> fieldMax = null; // generate constants for field ids ... for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { if (jf.getOrdinal() > fieldOrdinalMax) { fieldOrdinalMax = jf.getOrdinal(); fieldMax = jf; } cb.append("public static final int Field_"+ jf.getName().toUpperCase()+" = " + Integer.toString(jf.getOrdinal()) + ";\n"); } } cb.append("static final int FieldID_MAX=Field_"+fieldMax.getName().toUpperCase()+";\n"); cb.append("\n"); if (this.enums.size() != 0) { cb.append("// Enumerations\n\n"); for (JEnum e : this.enums) { cb.append("// Enum:"+e.getName()+"\n"); cb.append("public static final class "+e.getName() + " {\n"); for (JEnumValue v : e.getValues()) { cb.append("public static final int "+v.getName()+" = "+Integer.toString(v.getValue()) + ";\n"); } // next generate a enum value to desc method cb.append("\n"); cb.append("public static String toString(int enumValue){\n"); HashSet<Integer> visited = new HashSet<Integer>(); cb.append("switch (enumValue) {\n"); for (JEnumValue v : e.getValues()) { if (!visited.contains(v.getValue())) { cb.append("case " + v.getValue()+": return \""+v.getName() + "\";\n"); visited.add(v.getValue()); } } cb.append("default: return \"\";\n"); cb.append("}\n"); cb.append("}\n"); cb.append("}\n"); } } cb.append("// Field Declarations\n"); if (trackDirtyFields()){ cb.append("private BitSet __validFields = new BitSet(FieldID_MAX+1);\n\n"); } //TODO: FIX FIELD DECLARATIONS AS NECESSARY for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); String name = jf.getName(); JavaType type = jf.getType(); type.genDecl(cb, name); } cb.append("\n"); cb.append("// Default Constructor\n"); //TODO: FIX DEFAULT CONSTRUCTOR AS NECESSARY cb.append("public "+name+"() { }\n\n"); cb.append("// Accessors\n\n"); if (trackDirtyFields()) { cb.append("public final boolean isFieldDirty(int fieldId) { return __validFields.get(fieldId); }\n"); cb.append("public final void setFieldDirty(int fieldId) { __validFields.set(fieldId); }\n\n"); cb.append("public final void setFieldClean(int fieldId) { __validFields.clear(fieldId); }\n\n"); } else { cb.append("public final boolean isFieldDirty(int fieldId) { return true; }\n"); cb.append("public final void setFieldDirty(int fieldId) { }\n\n"); cb.append("public final void setFieldClean(int fieldId) { }\n\n"); } //TODO: FIX GET SET IF NECESSARY for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); String name = jf.getName(); JavaType type = jf.getType(); type.genGetSet(cb, name,(jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0 && trackDirtyFields()); } cb.append("// Object Dirty support \n\n"); if (trackDirtyFields()) { cb.append("public final boolean isObjectDirty(){\n"); cb.append("boolean isDirty = !__validFields.isEmpty();\n"); boolean requiresNestedCheck = false; // now if the object has nested complex types ... for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); if (type.hasDirtyState()) { if (requiresNestedCheck == false) { cb.append("if (!isDirty){\n"); requiresNestedCheck = true; } type.genDirtyCheck(cb,name); } } } if (requiresNestedCheck) { cb.append("}\n"); } cb.append("return isDirty;\n"); cb.append("}\n"); } else { cb.append("public final boolean isObjectDirty(){ return true; } \n"); } cb.append("\n"); cb.append("// serialize implementation \n"); //TODO: FIX SERIALIZE cb.append("public final void serialize("+ "DataOutput output,BinaryProtocol encoder)\n"+ "throws java.io.IOException {\n"); cb.append("encoder.beginFields(output);\n"); for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); int ordinal = jf.getOrdinal(); cb.append("// serialize field:"+name+"\n"); if (trackDirtyFields()) { // use type specific validity check (to address dirtying of child objects properly) if (type.hasDirtyState()) { type.genValidFieldCheck(cb, name); } else { cb.append("if (__validFields.get(Field_"+name.toUpperCase()+"))"); } } cb.append("{\n"); // ok if field tracks dirty state and we are serializing dirty state if (trackDirtyFields() && type.hasDirtyState()) { // modify source object's dirty flags cb.append("__validFields.set(Field_"+name.toUpperCase()+");\n"); } cb.append("encoder.beginField(output,\""+name+"\",Field_"+name.toUpperCase()+");\n"); type.genWriteMethod(cb, name, name); //cb.append("encoder.endField(output,\""+name+"\",Field_"+name.toUpperCase()+");\n"); cb.append("}\n"); if (trackDirtyFields() && type.hasDirtyState()) { cb.append("else {\n"); // synchronize dirty state for this complex type with parent object cb.append("__validFields.clear(Field_"+name.toUpperCase()+");\n"); cb.append("}\n"); } } } cb.append("encoder.endFields(output);\n"); cb.append("}\n"); cb.append("// skip to implementation \n"); cb.append("public static final int skipTo(DataInputBuffer input, BinaryProtocol decoder,int targetFieldId) throws java.io.IOException {\n"); //cb.append("System.out.println(\"skipTo callendOn Type:" + fullName + " targetFieldId:\" + targetFieldId);\n"); cb.append("// keep reading fields until terminator (-1) is located \n"); cb.append("int fieldId;\n"); cb.append("input.mark(-1);\n"); cb.append("while ((fieldId = decoder.readFieldId(input)) != -1) { \n"); //cb.append("System.out.println(\"got fieldId:\" + fieldId);\n"); // terminate early if field id is located ... cb.append(" if (targetFieldId == fieldId) {\n"); //cb.append(" System.out.println(\"match! Exiting\");\n"); cb.append(" return fieldId;\n"); cb.append(" }\n"); cb.append(" else if (fieldId > targetFieldId) {\n"); //cb.append(" System.out.println(\"Exceeded Bounds.Pre Reset:\" + input.getPosition());\n"); cb.append(" input.reset();\n"); //cb.append(" System.out.println(\"Exceeded Bounds.Post Reset:\" + input.getPosition());\n"); cb.append(" return fieldId;\n"); cb.append(" }\n"); cb.append(" else {\n"); cb.append("switch (fieldId) { \n"); for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); cb.append("case Field_"+name.toUpperCase()+":{\n"); type.genSkipMethod(cb); cb.append("}\n"); cb.append("break;\n"); } } cb.append("}\n"); cb.append("}\n"); cb.append("input.mark(-1);\n"); cb.append("}\n"); //cb.append("System.out.println(\"exiting got terminating -1 fieldId\");\n"); cb.append("return -1;\n"); cb.append("}\n"); cb.append("// deserialize implementation \n"); //TODO: FIX DESERIALIZE cb.append("public final void deserialize("+ "DataInput input, BinaryProtocol decoder)\n"+ "throws java.io.IOException {\n"); cb.append("// clear existing data first \n"); cb.append("clear();\n\n"); cb.append("// reset protocol object to unknown field id enconding mode (for compatibility)\n"); cb.append("decoder.pushFieldIdEncodingMode(BinaryProtocol.FIELD_ID_ENCODING_MODE_UNKNOWN);\n"); cb.append("// keep reading fields until terminator (-1) is located \n"); cb.append("int fieldId;\n"); cb.append("while ((fieldId = decoder.readFieldId(input)) != -1) { \n"); cb.append("switch (fieldId) { \n"); for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); cb.append("case Field_"+name.toUpperCase()+":{\n"); if (trackDirtyFields()) { cb.append("__validFields.set(Field_"+name.toUpperCase()+");\n"); } type.genReadMethod(cb, name, name, false); cb.append("}\n"); cb.append("break;\n"); } } cb.append("}\n"); cb.append("}\n"); cb.append("// pop extra encoding mode off of stack \n"); cb.append("decoder.popFieldIdEncodingMode();\n"); cb.append("}\n"); cb.append("// clear implementation \n"); //TODO: ADD CLEAR cb.append("public final void clear() {\n"); if ((modifiers & Modifiers.HAS_RECORDID) != 0) { cb.append("super.clear();\n"); } if (trackDirtyFields()) { cb.append("__validFields.clear();\n"); } for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); String name = jf.getName(); JavaType type = jf.getType(); int ordinal = jf.getOrdinal(); type.genClearMethod(cb, name); } cb.append("}\n"); cb.append("// equals implementation \n"); //TODO: FIX EQUALS cb.append("public final boolean equals(final Object peer_) {\n"); cb.append("if (!(peer_ instanceof "+name+")) {\n"); cb.append("return false;\n"); cb.append("}\n"); cb.append("if (peer_ == this) {\n"); cb.append("return true;\n"); cb.append("}\n"); cb.append(name+" peer = ("+name+") peer_;\n"); if (trackDirtyFields()) { cb.append("boolean ret = __validFields.equals(peer.__validFields);\n"); cb.append("if (!ret) return ret;\n"); } else { cb.append("boolean ret = true;\n"); } for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); if (trackDirtyFields()) { if (type.hasDirtyState()) { type.genValidFieldCheck(cb, name); } else { cb.append("if (__validFields.get(Field_"+name.toUpperCase()+"))"); } } cb.append(" {\n"); type.genEquals(cb, name, "peer."+name); cb.append("if (!ret) return ret;\n"); cb.append("}\n"); } } cb.append("return ret;\n"); cb.append("}\n"); // toString implementation cb.append("public final String toString() {\n"); cb.append("StringWriter sw = new StringWriter();\n"); cb.append("JsonWriter writer = new JsonWriter(sw);\n"); cb.append("toJSON(writer);\n"); cb.append("return sw.toString();\n"); cb.append("}\n"); cb.append("public final void toJSON(JsonWriter writer) {\n"); cb.append("try {\n"); cb.append("writer.beginObject();\n"); for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); if (trackDirtyFields()) { if (type.hasDirtyState()) { type.genValidFieldCheck(cb, name); } else { cb.append("if (__validFields.get(Field_"+name.toUpperCase()+"))"); } } cb.append(" {\n"); type.genJSON(cb, name); cb.append("}\n"); } } cb.append("writer.endObject();\n"); cb.append("writer.flush();\n"); cb.append("}\n"); cb.append("catch (IOException e){\n"); cb.append(" throw new RuntimeException(e);\n"); cb.append("}\n"); cb.append("}\n"); cb.append("// clone implementation \n"); cb.append("@SuppressWarnings(\"unchecked\")\n"); cb.append("public final Object clone() throws CloneNotSupportedException {\n"); cb.append(name+" other = new "+name+"();\n"); if (trackDirtyFields()) { cb.append("other.__validFields.or(this.__validFields);\n"); } for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); String name = jf.getName(); JavaType type = jf.getType(); if (trackDirtyFields()) { if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0 && !type.hasDirtyState()) { cb.append("if (__validFields.get(Field_"+name.toUpperCase()+"))"); } } cb.append("{\n"); type.genClone(cb,type.getType(), "other."+name,"this."+name); cb.append("}\n"); } cb.append("return other;\n"); cb.append("}\n"); cb.append("// merge implementation \n"); cb.append("@SuppressWarnings(\"unchecked\")\n"); cb.append("public final void merge(Object peer_) throws CloneNotSupportedException {\n"); cb.append(name+" peer = ("+name+") peer_;\n"); if (trackDirtyFields()) { cb.append("__validFields.or(peer.__validFields);\n"); } for (Iterator<JField<JavaType>> i = fields.iterator(); i.hasNext();) { JField<JavaType> jf = i.next(); String name = jf.getName(); JavaType type = jf.getType(); if (trackDirtyFields()) { if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0 && !type.hasDirtyState()) { cb.append("if (peer.__validFields.get(Field_"+name.toUpperCase()+"))"); } } cb.append("{\n"); type.genMerge(cb,type.getType(), "this."+name,"peer."+name); cb.append("}\n"); } cb.append("}\n"); cb.append("// hashCode implementation \n"); //TODO: FIX HASH CODE cb.append("public final int hashCode() {\n"); cb.append("int result = 1;\n"); Iterable<JField<JavaType>> fieldIterator = null; if (getKeyCount() != 0) { fieldIterator = getKeys(); } else { fieldIterator = fields; } for (JField<JavaType> jf : fieldIterator) { if ((jf.getModifiers() & JField.Modifiers.TRANSIENT) == 0) { String name = jf.getName(); JavaType type = jf.getType(); type.genHashCode(cb, name); } } cb.append("return result;\n"); cb.append("}\n"); cb.append("}\n"); jj.write(cb.toString()); jj.close(); } @Override void genJSON(CodeBuffer cb, String fname) throws IOException { cb.append(fname+".toJSON(writer);\n"); } @Override void genMerge(CodeBuffer cb, String type, String targetField,String sourceField) { cb.append(targetField + ".merge(" + sourceField + ");\n"); } @Override void genClearMethod(CodeBuffer cb, String fname) { cb.append(fname+".clear();\n"); } /** does this type have an independent dirty state - ignores validFields bit**/ boolean hasDirtyState() { return true; } void genDirtyCheck(CodeBuffer cb,String fieldName) { cb.append("if (!isDirty){\n"); cb.append("isDirty="+fieldName+".isObjectDirty();\n"); cb.append("}\n"); } void genValidFieldCheck(CodeBuffer cb,String fieldName) { cb.append("if ("+fieldName+".isObjectDirty())"); } } class CppRecord extends CppCompType { private String fullName; private String name; private String module; private ArrayList<JField<CppType>> fields = new ArrayList<JField<CppType>>(); CppRecord(String name, ArrayList<JField<JType>> flist) { super(name.replaceAll("\\.","::")); this.fullName = name.replaceAll("\\.", "::"); int idx = name.lastIndexOf('.'); this.name = name.substring(idx+1); this.module = name.substring(0, idx).replaceAll("\\.", "::"); for (Iterator<JField<JType>> iter = flist.iterator(); iter.hasNext();) { JField<JType> f = iter.next(); fields.add(new JField<CppType>(f.getName(), f.getType().getCppType(),f.getOrdinal(),f.getModifiers())); } } String genDecl(String fname) { return " "+name+" "+fname+";\n"; } void genCode(FileWriter hh, FileWriter cc, ArrayList<String> options) throws IOException { CodeBuffer hb = new CodeBuffer(); String[] ns = module.split("::"); for (int i = 0; i < ns.length; i++) { hb.append("namespace "+ns[i]+" {\n"); } hb.append("class "+name+" : public ::hadoop::Record {\n"); hb.append("private:\n"); for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) { JField<CppType> jf = i.next(); String name = jf.getName(); CppType type = jf.getType(); type.genDecl(hb, name); } hb.append("public:\n"); hb.append("virtual void serialize(::hadoop::OArchive& a_, const char* tag) const;\n"); hb.append("virtual void deserialize(::hadoop::IArchive& a_, const char* tag);\n"); hb.append("virtual const ::std::string& type() const;\n"); hb.append("virtual const ::std::string& signature() const;\n"); hb.append("virtual bool operator<(const "+name+"& peer_) const;\n"); hb.append("virtual bool operator==(const "+name+"& peer_) const;\n"); hb.append("virtual ~"+name+"() {};\n"); for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) { JField<CppType> jf = i.next(); String name = jf.getName(); CppType type = jf.getType(); type.genGetSet(hb, name); } hb.append("}; // end record "+name+"\n"); for (int i=ns.length-1; i>=0; i--) { hb.append("} // end namespace "+ns[i]+"\n"); } hh.write(hb.toString()); CodeBuffer cb = new CodeBuffer(); cb.append("void "+fullName+"::serialize(::hadoop::OArchive& a_, const char* tag) const {\n"); cb.append("a_.startRecord(*this,tag);\n"); for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) { JField<CppType> jf = i.next(); String name = jf.getName(); CppType type = jf.getType(); if (type instanceof JBuffer.CppBuffer) { cb.append("a_.serialize("+name+","+name+".length(),\""+name+"\");\n"); } else { cb.append("a_.serialize("+name+",\""+name+"\");\n"); } } cb.append("a_.endRecord(*this,tag);\n"); cb.append("return;\n"); cb.append("}\n"); cb.append("void "+fullName+"::deserialize(::hadoop::IArchive& a_, const char* tag) {\n"); cb.append("a_.startRecord(*this,tag);\n"); for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) { JField<CppType> jf = i.next(); String name = jf.getName(); CppType type = jf.getType(); if (type instanceof JBuffer.CppBuffer) { cb.append("{\nsize_t len=0; a_.deserialize("+name+",len,\""+name+"\");\n}\n"); } else { cb.append("a_.deserialize("+name+",\""+name+"\");\n"); } } cb.append("a_.endRecord(*this,tag);\n"); cb.append("return;\n"); cb.append("}\n"); cb.append("bool "+fullName+"::operator< (const "+fullName+"& peer_) const {\n"); cb.append("return (1\n"); for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) { JField<CppType> jf = i.next(); String name = jf.getName(); cb.append("&& ("+name+" < peer_."+name+")\n"); } cb.append(");\n"); cb.append("}\n"); cb.append("bool "+fullName+"::operator== (const "+fullName+"& peer_) const {\n"); cb.append("return (1\n"); for (Iterator<JField<CppType>> i = fields.iterator(); i.hasNext();) { JField<CppType> jf = i.next(); String name = jf.getName(); cb.append("&& ("+name+" == peer_."+name+")\n"); } cb.append(");\n"); cb.append("}\n"); cb.append("const ::std::string&"+fullName+"::type() const {\n"); cb.append("static const ::std::string type_(\""+name+"\");\n"); cb.append("return type_;\n"); cb.append("}\n"); cb.append("const ::std::string&"+fullName+"::signature() const {\n"); cb.append("static const ::std::string sig_(\""+getSignature()+"\");\n"); cb.append("return sig_;\n"); cb.append("}\n"); cc.write(cb.toString()); } } class CRecord extends CCompType { } private String signature; /** * Creates a new instance of JRecord */ public JRecord(String name, ArrayList<JField<JType>> flist,ArrayList<JEnum> enums,Set<String> modifiers,ArrayList<JComparator> comparators) { setJavaType(new JavaRecord(name,flist,enums,modifiers)); setCppType(new CppRecord(name, flist)); setCType(new CRecord()); // precompute signature int idx = name.lastIndexOf('.'); String recName = name.substring(idx+1); StringBuffer sb = new StringBuffer(); sb.append("L").append(recName).append("("); for (Iterator<JField<JType>> i = flist.iterator(); i.hasNext();) { String s = i.next().getType().getSignature(); sb.append(s); } sb.append(")"); signature = sb.toString(); } String getSignature() { return signature; } void genCppCode(FileWriter hh, FileWriter cc, ArrayList<String> options) throws IOException { ((CppRecord)getCppType()).genCode(hh, cc, options); } void genJavaCode(String destDir, ArrayList<String> options) throws IOException { ((JavaRecord)getJavaType()).genCode(destDir, options); } }