JRecord.java
/*
* 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.apache.jute.compiler;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.jute.compiler.generated.RccConstants;
import org.apache.jute.compiler.generated.Token;
/**
*
*/
public class JRecord extends JCompType {
private String mFQName;
private String mName;
private String mModule;
private List<JField> mFields;
private Token mRecordToken;
/**
* Creates a new instance of JRecord.
*/
public JRecord(String name, ArrayList<JField> flist, Token recordToken) {
super("struct " + name.substring(name.lastIndexOf('.') + 1),
name.replaceAll("\\.", "::"), getCsharpFQName(name), name, "Record", name, getCsharpFQName("IRecord"));
mFQName = name;
int idx = name.lastIndexOf('.');
mName = name.substring(idx + 1);
mModule = name.substring(0, idx);
mFields = flist;
mRecordToken = recordToken;
}
public String getName() {
return mName;
}
public Token getRecordToken() {
return mRecordToken;
}
public String getCsharpName() {
return "Id".equals(mName) ? "ZKId" : mName;
}
public String getJavaFQName() {
return mFQName;
}
public String getCppFQName() {
return mFQName.replaceAll("\\.", "::");
}
public String getJavaPackage() {
return mModule;
}
public String getCppNameSpace() {
return mModule.replaceAll("\\.", "::");
}
public String getCsharpNameSpace() {
String[] parts = mModule.split("\\.");
StringBuffer namespace = new StringBuffer();
for (int i = 0; i < parts.length; i++) {
String capitalized = parts[i].substring(0, 1).toUpperCase() + parts[i].substring(1).toLowerCase();
namespace.append(capitalized);
if (i != parts.length - 1) {
namespace.append(".");
}
}
return namespace.toString();
}
public List<JField> getFields() {
return mFields;
}
public String getSignature() {
StringBuilder sb = new StringBuilder();
sb.append("L").append(mName).append("(");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); ) {
String s = i.next().getSignature();
sb.append(s);
}
sb.append(")");
return sb.toString();
}
public String genCppDecl(String fname) {
return " " + getCppNameSpace() + "::" + mName + " m" + fname + ";\n";
}
public String genJavaReadMethod(String fname, String tag) {
return genJavaReadWrapper(fname, tag, false);
}
public String genJavaReadWrapper(String fname, String tag, boolean decl) {
StringBuilder ret = new StringBuilder("");
if (decl) {
ret.append(" " + getJavaFQName() + " " + fname + ";\n");
}
ret.append(" " + fname + "= new " + getJavaFQName() + "();\n");
ret.append(" a_.readRecord(" + fname + ",\"" + tag + "\");\n");
return ret.toString();
}
public String genJavaWriteWrapper(String fname, String tag) {
return " a_.writeRecord(" + fname + ",\"" + tag + "\");\n";
}
String genCsharpReadMethod(String fname, String tag) {
//return " "+capitalize(fname)+"=a_.Read"+mMethodSuffix+"(" + capitalize(fname) + ",\""+tag+"\");\n";
return genCsharpReadWrapper(capitalize(fname), tag, false);
}
public String genCsharpReadWrapper(String fname, String tag, boolean decl) {
StringBuilder ret = new StringBuilder("");
if (decl) {
ret.append(" " + getCsharpFQName(mFQName) + " " + fname + ";\n");
}
ret.append(" " + fname + "= new " + getCsharpFQName(mFQName) + "();\n");
ret.append(" a_.ReadRecord(" + fname + ",\"" + tag + "\");\n");
return ret.toString();
}
public String genCsharpWriteWrapper(String fname, String tag) {
return " a_.WriteRecord(" + fname + ",\"" + tag + "\");\n";
}
static Map<String, String> vectorStructs = new HashMap<>();
public void genCCode(FileWriter h, FileWriter c) throws IOException {
for (JField f : mFields) {
if (f.getType() instanceof JVector) {
JVector jv = (JVector) f.getType();
JType jvType = jv.getElementType();
String structName = JVector.extractVectorName(jvType);
if (vectorStructs.get(structName) == null) {
vectorStructs.put(structName, structName);
h.write("struct " + structName + " {\n int32_t count;\n" + jv.getElementType().genCDecl("*data") + "\n};\n");
h.write("int serialize_" + structName + "(struct oarchive *out, const char *tag, struct " + structName + " *v);\n");
h.write("int deserialize_" + structName + "(struct iarchive *in, const char *tag, struct " + structName + " *v);\n");
h.write("int allocate_" + structName + "(struct " + structName + " *v, int32_t len);\n");
h.write("int deallocate_" + structName + "(struct " + structName + " *v);\n");
c.write("int allocate_" + structName + "(struct " + structName + " *v, int32_t len) {\n");
c.write(" if (!len) {\n");
c.write(" v->count = 0;\n");
c.write(" v->data = 0;\n");
c.write(" } else {\n");
c.write(" v->count = len;\n");
c.write(" v->data = calloc(sizeof(*v->data), len);\n");
c.write(" }\n");
c.write(" return 0;\n");
c.write("}\n");
c.write("int deallocate_" + structName + "(struct " + structName + " *v) {\n");
c.write(" if (v->data) {\n");
c.write(" int32_t i;\n");
c.write(" for(i=0;i<v->count; i++) {\n");
c.write(" deallocate_" + JRecord.extractMethodSuffix(jvType) + "(&v->data[i]);\n");
c.write(" }\n");
c.write(" free(v->data);\n");
c.write(" v->data = 0;\n");
c.write(" }\n");
c.write(" return 0;\n");
c.write("}\n");
c.write("int serialize_" + structName + "(struct oarchive *out, const char *tag, struct " + structName + " *v)\n");
c.write("{\n");
c.write(" int32_t count = v->count;\n");
c.write(" int rc = 0;\n");
c.write(" int32_t i;\n");
c.write(" rc = out->start_vector(out, tag, &count);\n");
c.write(" for(i=0;i<v->count;i++) {\n");
genSerialize(c, jvType, "data", "data[i]");
c.write(" }\n");
c.write(" rc = rc ? rc : out->end_vector(out, tag);\n");
c.write(" return rc;\n");
c.write("}\n");
c.write("int deserialize_" + structName + "(struct iarchive *in, const char *tag, struct " + structName + " *v)\n");
c.write("{\n");
c.write(" int rc = 0;\n");
c.write(" int32_t i;\n");
c.write(" rc = in->start_vector(in, tag, &v->count);\n");
c.write(" v->data = calloc(v->count, sizeof(*v->data));\n");
c.write(" for(i=0;i<v->count;i++) {\n");
genDeserialize(c, jvType, "value", "data[i]");
c.write(" }\n");
c.write(" rc = in->end_vector(in, tag);\n");
c.write(" return rc;\n");
c.write("}\n");
}
}
}
String recName = getName();
String recordComments = getRecordComments();
if (recordComments != null && !recordComments.isEmpty()) {
h.write(recordComments);
}
h.write("struct " + recName + " {\n");
for (JField f : mFields) {
String fieldComments = getCFieldComments(f);
if (fieldComments != null && !fieldComments.isEmpty()) {
h.write(fieldComments);
}
h.write(f.genCDecl());
}
h.write("};\n");
h.write("int serialize_" + recName + "(struct oarchive *out, const char *tag, struct " + recName + " *v);\n");
h.write("int deserialize_" + recName + "(struct iarchive *in, const char *tag, struct " + recName + "*v);\n");
h.write("void deallocate_" + recName + "(struct " + recName + "*);\n");
c.write("int serialize_" + recName + "(struct oarchive *out, const char *tag, struct " + recName + " *v)");
c.write("{\n");
c.write(" int rc;\n");
c.write(" rc = out->start_record(out, tag);\n");
for (JField f : mFields) {
genSerialize(c, f.getType(), f.getTag(), f.getName());
}
c.write(" rc = rc ? rc : out->end_record(out, tag);\n");
c.write(" return rc;\n");
c.write("}\n");
c.write("int deserialize_" + recName + "(struct iarchive *in, const char *tag, struct " + recName + "*v)");
c.write("{\n");
c.write(" int rc;\n");
c.write(" rc = in->start_record(in, tag);\n");
for (JField f : mFields) {
genDeserialize(c, f.getType(), f.getTag(), f.getName());
}
c.write(" rc = rc ? rc : in->end_record(in, tag);\n");
c.write(" return rc;\n");
c.write("}\n");
c.write("void deallocate_" + recName + "(struct " + recName + "*v)");
c.write("{\n");
for (JField f : mFields) {
if (f.getType() instanceof JRecord) {
c.write(" deallocate_" + extractStructName(f.getType()) + "(&v->" + f.getName() + ");\n");
} else if (f.getType() instanceof JVector) {
JVector vt = (JVector) f.getType();
c.write(" deallocate_" + JVector.extractVectorName(vt.getElementType()) + "(&v->" + f.getName() + ");\n");
} else if (f.getType() instanceof JCompType) {
c.write(" deallocate_" + extractMethodSuffix(f.getType()) + "(&v->" + f.getName() + ");\n");
}
}
c.write("}\n");
}
private void genSerialize(FileWriter c, JType type, String tag, String name) throws IOException {
if (type instanceof JRecord) {
c.write(" rc = rc ? rc : serialize_" + extractStructName(type) + "(out, \"" + tag + "\", &v->" + name + ");\n");
} else if (type instanceof JVector) {
c.write(" rc = rc ? rc : serialize_" + JVector.extractVectorName(((JVector) type).getElementType()) + "(out, \"" + tag + "\", &v->" + name + ");\n");
} else {
c.write(" rc = rc ? rc : out->serialize_" + extractMethodSuffix(type) + "(out, \"" + tag + "\", &v->" + name + ");\n");
}
}
private void genDeserialize(FileWriter c, JType type, String tag, String name) throws IOException {
if (type instanceof JRecord) {
c.write(" rc = rc ? rc : deserialize_" + extractStructName(type) + "(in, \"" + tag + "\", &v->" + name + ");\n");
} else if (type instanceof JVector) {
c.write(" rc = rc ? rc : deserialize_" + JVector.extractVectorName(((JVector) type).getElementType()) + "(in, \"" + tag + "\", &v->" + name + ");\n");
} else {
c.write(" rc = rc ? rc : in->deserialize_" + extractMethodSuffix(type) + "(in, \"" + tag + "\", &v->" + name + ");\n");
}
}
static String extractMethodSuffix(JType t) {
if (t instanceof JRecord) {
return extractStructName(t);
}
return t.getMethodSuffix();
}
private static String extractStructName(JType t) {
String type = t.getCType();
if (!type.startsWith("struct ")) {
return type;
}
return type.substring("struct ".length());
}
public void genCppCode(FileWriter hh, FileWriter cc)
throws IOException {
String[] ns = getCppNameSpace().split("::");
for (int i = 0; i < ns.length; i++) {
hh.write("namespace " + ns[i] + " {\n");
}
hh.write("class " + getName() + " : public ::hadoop::Record {\n");
hh.write("private:\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); ) {
JField jf = i.next();
hh.write(jf.genCppDecl());
}
hh.write(" mutable std::bitset<" + mFields.size() + "> bs_;\n");
hh.write("public:\n");
hh.write(" virtual void serialize(::hadoop::OArchive& a_, const char* tag) const;\n");
hh.write(" virtual void deserialize(::hadoop::IArchive& a_, const char* tag);\n");
hh.write(" virtual const ::std::string& type() const;\n");
hh.write(" virtual const ::std::string& signature() const;\n");
hh.write(" virtual bool validate() const;\n");
hh.write(" virtual bool operator<(const " + getName() + "& peer_) const;\n");
hh.write(" virtual bool operator==(const " + getName() + "& peer_) const;\n");
hh.write(" virtual ~" + getName() + "() {};\n");
int fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
hh.write(jf.genCppGetSet(fIdx));
}
hh.write("}; // end record " + getName() + "\n");
for (int i = ns.length - 1; i >= 0; i--) {
hh.write("} // end namespace " + ns[i] + "\n");
}
cc.write("void " + getCppFQName() + "::serialize(::hadoop::OArchive& a_, const char* tag) const {\n");
cc.write(" if (!validate()) throw new ::hadoop::IOException(\"All fields not set.\");\n");
cc.write(" a_.startRecord(*this,tag);\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
String name = jf.getName();
if (jf.getType() instanceof JBuffer) {
cc.write(" a_.serialize(m" + name + ",m" + name + ".length(),\"" + jf.getTag() + "\");\n");
} else {
cc.write(" a_.serialize(m" + name + ",\"" + jf.getTag() + "\");\n");
}
cc.write(" bs_.reset(" + fIdx + ");\n");
}
cc.write(" a_.endRecord(*this,tag);\n");
cc.write(" return;\n");
cc.write("}\n");
cc.write("void " + getCppFQName() + "::deserialize(::hadoop::IArchive& a_, const char* tag) {\n");
cc.write(" a_.startRecord(*this,tag);\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
String name = jf.getName();
if (jf.getType() instanceof JBuffer) {
cc.write(" { size_t len=0; a_.deserialize(m" + name + ",len,\"" + jf.getTag() + "\");}\n");
} else {
cc.write(" a_.deserialize(m" + name + ",\"" + jf.getTag() + "\");\n");
}
cc.write(" bs_.set(" + fIdx + ");\n");
}
cc.write(" a_.endRecord(*this,tag);\n");
cc.write(" return;\n");
cc.write("}\n");
cc.write("bool " + getCppFQName() + "::validate() const {\n");
cc.write(" if (bs_.size() != bs_.count()) return false;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = (JField) i.next();
JType type = jf.getType();
if (type instanceof JRecord) {
cc.write(" if (!m" + jf.getName() + ".validate()) return false;\n");
}
}
cc.write(" return true;\n");
cc.write("}\n");
cc.write("bool " + getCppFQName() + "::operator< (const " + getCppFQName() + "& peer_) const {\n");
cc.write(" return (1\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); ) {
JField jf = i.next();
String name = jf.getName();
cc.write(" && (m" + name + " < peer_.m" + name + ")\n");
}
cc.write(" );\n");
cc.write("}\n");
cc.write("bool " + getCppFQName() + "::operator== (const " + getCppFQName() + "& peer_) const {\n");
cc.write(" return (1\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); ) {
JField jf = i.next();
String name = jf.getName();
cc.write(" && (m" + name + " == peer_.m" + name + ")\n");
}
cc.write(" );\n");
cc.write("}\n");
cc.write("const ::std::string&" + getCppFQName() + "::type() const {\n");
cc.write(" static const ::std::string type_(\"" + mName + "\");\n");
cc.write(" return type_;\n");
cc.write("}\n");
cc.write("const ::std::string&" + getCppFQName() + "::signature() const {\n");
cc.write(" static const ::std::string sig_(\"" + getSignature() + "\");\n");
cc.write(" return sig_;\n");
cc.write("}\n");
}
public void genJavaCode(File outputDirectory) throws IOException {
String pkg = getJavaPackage();
String pkgpath = pkg.replaceAll("\\.", "/");
File pkgdir = new File(outputDirectory, pkgpath);
if (!pkgdir.exists()) {
// create the pkg directory
if (!pkgdir.mkdirs()) {
throw new IOException("Cannot create directory: " + pkgpath);
}
} else if (!pkgdir.isDirectory()) {
throw new IOException(pkgpath + " is not a directory.");
}
try (FileWriter jj = new FileWriter(new File(pkgdir, getName() + ".java"))) {
jj.write("// File generated by hadoop record compiler. Do not edit.\n");
jj.write("/**\n");
jj.write("* Licensed to the Apache Software Foundation (ASF) under one\n");
jj.write("* or more contributor license agreements. See the NOTICE file\n");
jj.write("* distributed with this work for additional information\n");
jj.write("* regarding copyright ownership. The ASF licenses this file\n");
jj.write("* to you under the Apache License, Version 2.0 (the\n");
jj.write("* \"License\"); you may not use this file except in compliance\n");
jj.write("* with the License. You may obtain a copy of the License at\n");
jj.write("*\n");
jj.write("* http://www.apache.org/licenses/LICENSE-2.0\n");
jj.write("*\n");
jj.write("* Unless required by applicable law or agreed to in writing, software\n");
jj.write("* distributed under the License is distributed on an \"AS IS\" BASIS,\n");
jj.write("* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
jj.write("* See the License for the specific language governing permissions and\n");
jj.write("* limitations under the License.\n");
jj.write("*/\n");
jj.write("\n");
jj.write("package " + getJavaPackage() + ";\n\n");
jj.write("import org.apache.jute.*;\n");
jj.write("import org.apache.jute.Record; // JDK14 needs explicit import due to clash with java.lang.Record\n");
jj.write("import org.apache.yetus.audience.InterfaceAudience;\n");
String recordComments = getRecordComments();
if (recordComments != null && !recordComments.isEmpty()) {
jj.write(recordComments);
}
jj.write("@InterfaceAudience.Public\n");
jj.write("public class " + getName() + " implements Record {\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); ) {
JField jf = i.next();
String fieldComments = getJavaFieldComments(jf);
if (fieldComments != null && !fieldComments.isEmpty()) {
jj.write(fieldComments);
}
jj.write(jf.genJavaDecl());
}
jj.write(" public " + getName() + "() {\n");
jj.write(" }\n");
jj.write(" public " + getName() + "(\n");
int fIdx = 0;
int fLen = mFields.size();
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaConstructorParam(jf.getName()));
jj.write((fLen - 1 == fIdx) ? "" : ",\n");
}
jj.write(") {\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaConstructorSet(jf.getName()));
}
jj.write(" }\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaGetSet(fIdx));
}
jj.write(" public void serialize(OutputArchive a_, String tag) throws java.io.IOException {\n");
jj.write(" a_.startRecord(this,tag);\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaWriteMethodName());
}
jj.write(" a_.endRecord(this,tag);\n");
jj.write(" }\n");
jj.write(" public void deserialize(InputArchive a_, String tag) throws java.io.IOException {\n");
jj.write(" a_.startRecord(tag);\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaReadMethodName());
}
jj.write(" a_.endRecord(tag);\n");
jj.write("}\n");
jj.write(" public String toString() {\n");
jj.write(" try {\n");
jj.write(" java.io.ByteArrayOutputStream s =\n");
jj.write(" new java.io.ByteArrayOutputStream();\n");
jj.write(" ToStringOutputArchive a_ = \n");
jj.write(" new ToStringOutputArchive(s);\n");
jj.write(" a_.startRecord(this,\"\");\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaWriteMethodName());
}
jj.write(" a_.endRecord(this,\"\");\n");
jj.write(" return new String(s.toByteArray(), java.nio.charset.StandardCharsets.UTF_8);\n");
jj.write(" } catch (Throwable ex) {\n");
jj.write(" ex.printStackTrace();\n");
jj.write(" }\n");
jj.write(" return \"ERROR\";\n");
jj.write(" }\n");
jj.write(" public void write(java.io.DataOutput out) throws java.io.IOException {\n");
jj.write(" BinaryOutputArchive archive = new BinaryOutputArchive(out);\n");
jj.write(" serialize(archive, \"\");\n");
jj.write(" }\n");
jj.write(" public void readFields(java.io.DataInput in) throws java.io.IOException {\n");
jj.write(" BinaryInputArchive archive = new BinaryInputArchive(in);\n");
jj.write(" deserialize(archive, \"\");\n");
jj.write(" }\n");
jj.write(" public int compareTo (Object peer_) throws ClassCastException {\n");
boolean unimplemented = false;
for (JField f : mFields) {
if ((f.getType() instanceof JMap)
|| (f.getType() instanceof JVector)) {
unimplemented = true;
}
}
if (unimplemented) {
jj.write(" throw new UnsupportedOperationException(\"comparing "
+ getName() + " is unimplemented\");\n");
} else {
jj.write(" if (!(peer_ instanceof " + getName() + ")) {\n");
jj.write(" throw new ClassCastException(\"Comparing different types of records.\");\n");
jj.write(" }\n");
jj.write(" " + getName() + " peer = (" + getName() + ") peer_;\n");
jj.write(" int ret = 0;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaCompareTo());
jj.write(" if (ret != 0) return ret;\n");
}
jj.write(" return ret;\n");
}
jj.write(" }\n");
jj.write(" public boolean equals(Object peer_) {\n");
jj.write(" if (!(peer_ instanceof " + getName() + ")) {\n");
jj.write(" return false;\n");
jj.write(" }\n");
jj.write(" if (peer_ == this) {\n");
jj.write(" return true;\n");
jj.write(" }\n");
jj.write(" " + getName() + " peer = (" + getName() + ") peer_;\n");
jj.write(" boolean ret = false;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaEquals());
jj.write(" if (!ret) return ret;\n");
}
jj.write(" return ret;\n");
jj.write(" }\n");
jj.write(" public int hashCode() {\n");
jj.write(" int result = 17;\n");
jj.write(" int ret;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
jj.write(jf.genJavaHashCode());
jj.write(" result = 37*result + ret;\n");
}
jj.write(" return result;\n");
jj.write(" }\n");
jj.write(" public static String signature() {\n");
jj.write(" return \"" + getSignature() + "\";\n");
jj.write(" }\n");
jj.write("}\n");
}
}
public void genCsharpCode(File outputDirectory) throws IOException {
if (!outputDirectory.exists()) {
// create the pkg directory
if (!outputDirectory.mkdirs()) {
throw new IOException("Cannot create directory: " + outputDirectory);
}
} else if (!outputDirectory.isDirectory()) {
throw new IOException(outputDirectory + " is not a directory.");
}
try (FileWriter cs = new FileWriter(new File(outputDirectory, getName() + ".cs"));) {
cs.write("// File generated by hadoop record compiler. Do not edit.\n");
cs.write("/**\n");
cs.write("* Licensed to the Apache Software Foundation (ASF) under one\n");
cs.write("* or more contributor license agreements. See the NOTICE file\n");
cs.write("* distributed with this work for additional information\n");
cs.write("* regarding copyright ownership. The ASF licenses this file\n");
cs.write("* to you under the Apache License, Version 2.0 (the\n");
cs.write("* \"License\"); you may not use this file except in compliance\n");
cs.write("* with the License. You may obtain a copy of the License at\n");
cs.write("*\n");
cs.write("* http://www.apache.org/licenses/LICENSE-2.0\n");
cs.write("*\n");
cs.write("* Unless required by applicable law or agreed to in writing, software\n");
cs.write("* distributed under the License is distributed on an \"AS IS\" BASIS,\n");
cs.write("* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n");
cs.write("* See the License for the specific language governing permissions and\n");
cs.write("* limitations under the License.\n");
cs.write("*/\n");
cs.write("\n");
cs.write("using System;\n");
cs.write("using Org.Apache.Jute;\n");
cs.write("\n");
cs.write("namespace " + getCsharpNameSpace() + "\n");
cs.write("{\n");
String className = getCsharpName();
cs.write("public class " + className + " : IRecord, IComparable \n");
cs.write("{\n");
cs.write(" public " + className + "() {\n");
cs.write(" }\n");
cs.write(" public " + className + "(\n");
int fIdx = 0;
int fLen = mFields.size();
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpConstructorParam(jf.getCsharpName()));
cs.write((fLen - 1 == fIdx) ? "" : ",\n");
}
cs.write(") {\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpConstructorSet(jf.getCsharpName()));
}
cs.write(" }\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpGetSet(fIdx));
cs.write("\n");
}
cs.write(" public void Serialize(IOutputArchive a_, String tag) {\n");
cs.write(" a_.StartRecord(this,tag);\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpWriteMethodName());
}
cs.write(" a_.EndRecord(this,tag);\n");
cs.write(" }\n");
cs.write(" public void Deserialize(IInputArchive a_, String tag) {\n");
cs.write(" a_.StartRecord(tag);\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpReadMethodName());
}
cs.write(" a_.EndRecord(tag);\n");
cs.write("}\n");
cs.write(" public override String ToString() {\n");
cs.write(" try {\n");
cs.write(" System.IO.MemoryStream ms = new System.IO.MemoryStream();\n");
cs.write(" MiscUtil.IO.EndianBinaryWriter writer =\n");
cs.write(" new MiscUtil.IO.EndianBinaryWriter(MiscUtil.Conversion.EndianBitConverter.Big, ms, System.Text.Encoding.UTF8);\n");
cs.write(" BinaryOutputArchive a_ = \n");
cs.write(" new BinaryOutputArchive(writer);\n");
cs.write(" a_.StartRecord(this,\"\");\n");
fIdx = 0;
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpWriteMethodName());
}
cs.write(" a_.EndRecord(this,\"\");\n");
cs.write(" ms.Position = 0;\n");
cs.write(" return System.Text.Encoding.UTF8.GetString(ms.ToArray());\n");
cs.write(" } catch (Exception ex) {\n");
cs.write(" Console.WriteLine(ex.StackTrace);\n");
cs.write(" }\n");
cs.write(" return \"ERROR\";\n");
cs.write(" }\n");
cs.write(" public void Write(MiscUtil.IO.EndianBinaryWriter writer) {\n");
cs.write(" BinaryOutputArchive archive = new BinaryOutputArchive(writer);\n");
cs.write(" Serialize(archive, \"\");\n");
cs.write(" }\n");
cs.write(" public void ReadFields(MiscUtil.IO.EndianBinaryReader reader) {\n");
cs.write(" BinaryInputArchive archive = new BinaryInputArchive(reader);\n");
cs.write(" Deserialize(archive, \"\");\n");
cs.write(" }\n");
cs.write(" public int CompareTo (object peer_) {\n");
boolean unimplemented = false;
for (JField f : mFields) {
if ((f.getType() instanceof JMap)
|| (f.getType() instanceof JVector)) {
unimplemented = true;
}
}
if (unimplemented) {
cs.write(" throw new InvalidOperationException(\"comparing "
+ getCsharpName() + " is unimplemented\");\n");
} else {
cs.write(" if (!(peer_ is " + getCsharpName() + ")) {\n");
cs.write(" throw new InvalidOperationException(\"Comparing different types of records.\");\n");
cs.write(" }\n");
cs.write(" " + getCsharpName() + " peer = (" + getCsharpName() + ") peer_;\n");
cs.write(" int ret = 0;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpCompareTo());
cs.write(" if (ret != 0) return ret;\n");
}
cs.write(" return ret;\n");
}
cs.write(" }\n");
cs.write(" public override bool Equals(object peer_) {\n");
cs.write(" if (!(peer_ is " + getCsharpName() + ")) {\n");
cs.write(" return false;\n");
cs.write(" }\n");
cs.write(" if (peer_ == this) {\n");
cs.write(" return true;\n");
cs.write(" }\n");
cs.write(" bool ret = false;\n");
cs.write(" " + getCsharpName() + " peer = (" + getCsharpName() + ")peer_;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpEquals());
cs.write(" if (!ret) return ret;\n");
}
cs.write(" return ret;\n");
cs.write(" }\n");
cs.write(" public override int GetHashCode() {\n");
cs.write(" int result = 17;\n");
cs.write(" int ret;\n");
for (Iterator<JField> i = mFields.iterator(); i.hasNext(); fIdx++) {
JField jf = i.next();
cs.write(jf.genCsharpHashCode());
cs.write(" result = 37*result + ret;\n");
}
cs.write(" return result;\n");
cs.write(" }\n");
cs.write(" public static string Signature() {\n");
cs.write(" return \"" + getSignature() + "\";\n");
cs.write(" }\n");
cs.write("}\n");
cs.write("}\n");
}
}
public static String getCsharpFQName(String name) {
String[] packages = name.split("\\.");
StringBuffer fQName = new StringBuffer();
for (int i = 0; i < packages.length; i++) {
String pack = packages[i];
pack = capitalize(pack);
pack = "Id".equals(pack) ? "ZKId" : pack;
fQName.append(capitalize(pack));
if (i != packages.length - 1) {
fQName.append(".");
}
}
return fQName.toString();
}
public String getJavaFieldComments(JField jField) {
return getFieldComments(jField, " ");
}
public String getCFieldComments(JField jField) {
return getFieldComments(jField, " ");
}
private String getFieldComments(JField jField, String indent) {
if (jField == null || jField.getTypeToken() == null || jField.getNextToken() == null) {
return "";
}
// get the comment before the line
Token beforeTheLineCommentToken = getCommentToken(jField.getTypeToken(), jField.getPreviousToken());
List<String> comments = extractComments(beforeTheLineCommentToken, Integer.MAX_VALUE);
Token endOfLineCommentToken = getCommentToken(jField.getNextToken(), null);
if (endOfLineCommentToken != null && jField.getTypeToken().beginLine == endOfLineCommentToken.beginLine) {
comments.addAll(extractComments(endOfLineCommentToken, endOfLineCommentToken.beginLine));
}
return formatComments(indent, comments);
}
private Token getCommentToken(Token token, Token previousToken) {
if (token == null || token.specialToken == null) {
return null;
}
Token commentToken = token.specialToken;
while (commentToken.specialToken != null) {
commentToken = commentToken.specialToken;
}
// Skip end of line comment belong to previous token.
while (previousToken != null && commentToken != null && commentToken.beginLine == previousToken.endLine) {
commentToken = commentToken.next;
}
return commentToken;
}
public String getRecordComments() {
if (getRecordToken() == null || getRecordToken().specialToken == null) {
return "";
}
// get the comments before the class
Token commentToken = getCommentToken(getRecordToken(), null);
return formatComments("", extractComments(commentToken, Integer.MAX_VALUE));
}
private static String formatComments(String indent, List<String> commentLines) {
if (commentLines == null || commentLines.isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder();
for (String line : commentLines) {
if (!line.isEmpty()) {
builder.append(indent).append(line);
}
builder.append(System.lineSeparator());
}
return builder.toString();
}
/**
* Extracts comments with indentation and line separator trimmed.
*
* <p>Empty line is represented as empty string.
*/
private static List<String> extractComments(Token token, int endLine) {
List<String> comments = new ArrayList<>();
if (token == null) {
return comments;
}
int nextLine = token.beginLine;
while (token != null && token.beginLine <= endLine) {
while (nextLine < token.beginLine) {
comments.add("");
nextLine++;
}
nextLine = token.endLine + 1;
switch (token.kind) {
case RccConstants.ONE_LINE_COMMENT:
comments.add(token.image);
break;
case RccConstants.MULTI_LINE_COMMENT: {
List<String> lines = Arrays.asList(token.image.split("\r|\n|\r\n"));
// First line captures no indentation.
comments.add(lines.get(0));
int indentSpaces = token.beginColumn - 1;
for (int i = 1; i < lines.size(); i++) {
String line = lines.get(i);
int j = 0;
while (j < indentSpaces && j < line.length()) {
if (line.charAt(j) != ' ') {
break;
}
j++;
}
comments.add(line.substring(j));
}
}
break;
default:
throw new IllegalStateException("expect comment token, but get token kind " + token.kind);
}
token = token.next;
}
return comments;
}
}