package org.commoncrawl.rpc.compiler;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JService {
public String _serviceName;
public ArrayList<JMethod> _methods = new ArrayList<JMethod>();
public JService(String serviceName,ArrayList<JMethod> methodList) {
_serviceName = serviceName;
_methods = methodList;
}
public void genJavaCode(String destDir, ArrayList<String> options) throws IOException {
String fullName = _serviceName;
int idx = _serviceName.lastIndexOf('.');
String module = _serviceName.substring(0, idx);
String name = _serviceName.substring(idx+1);
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 java.io.DataInput;\n");
cb.append("import java.io.DataInputStream;\n");
cb.append("import java.io.IOException;\n");
cb.append("import java.util.concurrent.CountDownLatch;\n");
cb.append("import org.commoncrawl.rpc.base.internal.*;\n");
cb.append("import org.commoncrawl.rpc.base.shared.*;\n");
cb.append("import org.apache.commons.logging.Log;\n");
cb.append("import org.apache.commons.logging.LogFactory;\n");
cb.append("import org.apache.hadoop.util.StringUtils;\n");
cb.append("\n");
// generate interface
cb.append("public interface "+ name +" extends Service {\n\n");
cb.append("public static final Log LOG_PRIVATE = LogFactory.getLog(" + name + ".class);");
cb.append(" /** interface specification **/\n\n");
for (JMethod method : _methods) {
JRecord.JavaRecord inputType = (method.getInputType() != null) ? (JRecord.JavaRecord) method.getInputType().getJavaType() : null;
JRecord.JavaRecord outputType = (method.getOutputType() != null) ? (JRecord.JavaRecord)method.getOutputType().getJavaType() : null;
String inputFullSpec = (inputType != null) ? inputType.getFullName() : "NullMessage";
String outputFullSpec = (outputType != null) ? outputType.getFullName() : "NullMessage";
String inputShortSpec = (inputType != null) ? inputType.getShortName() : "NullMessage";
String outputShortSpec = (outputType != null) ? outputType.getShortName() : "NullMessage";
String contextSpec = "AsyncContext<"+inputFullSpec+","+outputFullSpec+">";
cb.append("// method "+method.getName()+" (in "+inputFullSpec + ", out "+outputShortSpec+");\n");
cb.append("void "+method.getName()+"("+contextSpec+" rpcContext) throws RPCException;\n\n");
}
cb.append("/** server specification struct **/\n");
cb.append("public static Specification spec = new Specification(\""+name+"\",new "+name+".Dispatcher());\n\n");
// generate AsyncClientStub inner class
cb.append("// Async Client Stub\n");
cb.append("public static class AsyncStub extends Service.AsyncStub {\n\n");
cb.append("// constructor\n");
cb.append("public AsyncStub(AsyncClientChannel channel) {\nsuper(channel);\n}\n");
// generate async stub methods
for (JMethod method : _methods) {
JRecord.JavaRecord inputType = (method.getInputType() != null) ? (JRecord.JavaRecord) method.getInputType().getJavaType() : null;
JRecord.JavaRecord outputType = (method.getOutputType() != null) ? (JRecord.JavaRecord)method.getOutputType().getJavaType() : null;
String inputFullSpec = (inputType != null) ? inputType.getFullName() : "NullMessage";
String outputFullSpec = (outputType != null) ? outputType.getFullName() : "NullMessage";
String inputShortSpec = (inputType != null) ? inputType.getShortName() : "NullMessage";
String outputShortSpec = (outputType != null) ? outputType.getShortName() : "NullMessage";
cb.append("// public AsyncRequest<"+inputShortSpec+","+outputShortSpec+"> "+method.getName()+
"("+inputShortSpec+" input,AsyncRequest.Callback<"+inputShortSpec+","+outputShortSpec+"> callback) throws RPCException\n");
cb.append("public AsyncRequest<"+inputFullSpec+","+outputFullSpec+"> "+method.getName() + "(");
if (inputType != null) {
cb.append(inputFullSpec+" input,");
}
cb.append("AsyncRequest.Callback<"+inputFullSpec+","+outputFullSpec+"> callback) throws RPCException {\n");
cb.append("AsyncRequest<"+inputFullSpec+","+outputFullSpec+"> request = new AsyncRequest<"+inputFullSpec+","+outputFullSpec+">(spec._name,\""+method.getName()+"\", ");
if (inputType == null) {
cb.append("NullMessage.getSingleton(),");
}
else {
cb.append("input,");
}
if (outputType != null) {
cb.append(" new "+outputFullSpec+"()");
}
else {
cb.append(" NullMessage.getSingleton()");
}
cb.append(", callback);\n");
cb.append("getChannel().sendRequest(request);\n");
cb.append("return request;\n");
cb.append("}\n\n");
}
cb.append("}\n\n");
// generate BlockingStub ...
cb.append("// Blocking Client Stub\n");
cb.append("public static class BlockingStub extends Service.BlockingStub<"+name+".AsyncStub> {\n");
cb.append("// constructor\n ");
cb.append("\npublic BlockingStub(AsyncClientChannel channel) {\n");
cb.append("super(new AsyncStub(channel));\n");
cb.append("}\n\n");
// generate blocking stub methods
for (JMethod method : _methods) {
JRecord.JavaRecord inputType = (method.getInputType() != null) ? (JRecord.JavaRecord) method.getInputType().getJavaType() : null;
JRecord.JavaRecord outputType = (method.getOutputType() != null) ? (JRecord.JavaRecord)method.getOutputType().getJavaType() : null;
String inputFullSpec = (inputType != null) ? inputType.getFullName() : "NullMessage";
String outputFullSpec = (outputType != null) ? outputType.getFullName() : "NullMessage";
String inputShortSpec = (inputType != null) ? inputType.getShortName() : "NullMessage";
String outputShortSpec = (outputType != null) ? outputType.getShortName() : "NullMessage";
cb.append("// public "+outputShortSpec+" " +method.getName()+ "("+inputShortSpec+" input) throws RPCException\n");
cb.append("@SuppressWarnings(\"unchecked\")\n");
cb.append("public ");
if (outputType != null)
cb.append(outputFullSpec);
else
cb.append("void");
cb.append(" " +method.getName()+ "(");
if (inputType != null)
cb.append(inputFullSpec + " input");
cb.append(") throws RPCException {\n");
cb.append("\nfinal CountDownLatch latch = new CountDownLatch(1);\n\n");
cb.append("AsyncRequest<"+inputFullSpec+","+outputFullSpec+"> request = this.getAsyncStub()."+method.getName()+"(");
if (inputType != null)
cb.append("input,");
cb.append("new AsyncRequest.Callback(){\n\n");
cb.append("public void requestComplete(AsyncRequest request) {\n");
cb.append("latch.countDown();\n");
cb.append("}} );\n\n");
cb.append("try {\n");
cb.append("if (super.waitForResult(latch)) {\n");
if (outputType != null)
cb.append("return request.getOutput();\n");
else
cb.append("return;\n");
cb.append("}\n");
cb.append("throw new RPCException(\"RPC Timeout\");\n");
cb.append("}\n");
cb.append("catch (IOException e){\n");
cb.append("LOG_PRIVATE.error(StringUtils.stringifyException(e));\n");
cb.append("throw new RPCException(e);\n");
cb.append("}\n");
cb.append("}\n\n");
}
cb.append("}\n\n");
// generate server dispatcher
cb.append("/** typed dispatcher object **/\n");
cb.append("public static class Dispatcher implements org.commoncrawl.rpc.base.internal.Dispatcher {\n");
cb.append("//@Override\n");
cb.append("public AsyncContext dispatch(Server server,Frame.IncomingFrame frame,AsyncServerChannel serverChannel," +
"AsyncClientChannel clientChannel) throws RPCException {\n\n");
// generate dispatcher code per supported method ...
for (JMethod method : _methods) {
JRecord.JavaRecord inputType = (method.getInputType() != null) ? (JRecord.JavaRecord) method.getInputType().getJavaType() : null;
JRecord.JavaRecord outputType = (method.getOutputType() != null) ? (JRecord.JavaRecord)method.getOutputType().getJavaType() : null;
String inputFullSpec = (inputType != null) ? inputType.getFullName() : "NullMessage";
String outputFullSpec = (outputType != null) ? outputType.getFullName() : "NullMessage";
String inputShortSpec = (inputType != null) ? inputType.getShortName() : "NullMessage";
String outputShortSpec = (outputType != null) ? outputType.getShortName() : "NullMessage";
String contextSpec = "AsyncContext<"+inputFullSpec+","+outputFullSpec+">";
cb.append("if (frame._method.equals(\""+method.getName()+"\")){\n");
if (inputType != null) {
cb.append(inputFullSpec+" input = new "+inputFullSpec+"();\n");
}
else {
cb.append(inputFullSpec+ " input = NullMessage.getSingleton();\n");
}
if (outputType != null) {
cb.append(outputFullSpec+" output = new " + outputFullSpec+"();\n");
}
else {
cb.append(outputFullSpec+ " output = NullMessage.getSingleton();\n");
}
// skip for NullMessage ...
if (inputType != null) {
cb.append("try {\n");
cb.append("input.deserialize(new DataInputStream(frame._payload),new BinaryProtocol());\n");
cb.append("} catch (IOException e) {\n");
cb.append("LOG_PRIVATE.error(StringUtils.stringifyException(e));\n");
cb.append("throw new RPCException(e);\n");
cb.append("}\n");
cb.append("\n");
}
cb.append(contextSpec +" contextOut = new "+contextSpec+"(serverChannel,clientChannel,frame._requestId,input,output);\n");
cb.append("// Invoke "+method.getName()+"\n");
cb.append("(("+name+")server)."+method.getName()+"(contextOut);\n\n");
cb.append("return contextOut;\n");
cb.append("}\n\n");
}
cb.append("return null;\n\n");
cb.append("}\n");
cb.append("}\n");
// terminate interface specification
cb.append("}\n");
jj.write(cb.toString());
jj.close();
}
}