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(); } }