package gargl.generators; import gargl.typedefinitions.Function; import gargl.utilities.Parameter; import java.util.Map; import java.util.Map.Entry; import java.util.List; import java.util.Arrays; public class CSharpClassGenerator extends Generator { private static String CSHARP_CLASS_FORMAT = "using System;\n" + "using System.Net;\n" + "using System.IO;\n\n" + "public class %1$s \n" + "{\n" + "%2$s\n" + "}"; private static String CSHARP_METHOD_FORMAT = "public string %1$s \n" + "{\n" + "%2$s \n" + "}\n\n"; private static String CSHARP_METHOD_SIGNATURE = "%1$s (%2$s)"; private static String CSHARP_HEADER_FORMAT = "req.Headers.Add(%1$s);\n"; private static String CSHARP_HEADER_FORMAT_FIX = "req.%1$s = \"%2$s\";\n"; private static String CSHARP_HTTP_CONNECTION_FORMAT = "string url = %1$s;\n" + "HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);\n" + "req.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;\n\n" + "%2$s\n" + "HttpWebResponse resp = (HttpWebResponse)req.GetResponse();\n" + "int responseCode = (int)resp.StatusCode;\n" + "Console.WriteLine(\"Sending 'GET' request to URL : \" + url);\n" + "Console.WriteLine(\"Response Code : \" + responseCode);\n\n" + "string response;\n" + "using(StreamReader input = new StreamReader(resp.GetResponseStream()))\n" + "{\n" + "response = input.ReadToEnd();\n" + "}\n\n" +"Console.WriteLine(response.ToString());\n\n" + "return response.ToString();"; private static String CSHARP_POST_REQUEST_FORMAT = "string postData = \"%1$s\";\n" + "using(StreamWriter writer = new StreamWriter(req.GetRequestStream()))\n" + "{\n" + "writer.Write(postData);\n" + "writer.Flush();\n" + "}\n"; private static List<String> CSHARP_RESTRICTED_HEADERS = Arrays.asList( "Accept", "Connection", "Content-Length", "Content-Type", "Date", "Expect", "Host", "If-Modified-Since", "Keep-Alive", "Proxy-Connection", "Range", "Referer", "Transfer-Encoding", "User-Agent" ); public String generateFunction(Function function) { // Generate method signature using all necessary parameters String methodSignature = generateMethodSignature(function); // Generate strings for setting request method and headers String methodAndHeaders = generateMethodAndHeaders(function); // Generate querystring by appending url params and applying // formatting String queryString = generateQueryString(function); // Surround request.getUrl() with quotes if it is a parameter, and // do nothing if it is a parameter name String url = Parameter.processParameter(function.getUrl(), function) + " + \"?" + queryString + "\""; // Handle specifics for each type of request if ("POST".equals(function.getMethod())) { String postDataString = generatePostDataString(function.getPostData()); methodAndHeaders += String.format(CSHARP_POST_REQUEST_FORMAT, postDataString); } else if ("GET".equals(function.getMethod())) { // Currently there is no special behavior for GET requests } // Insert connection specific properties into connection format // string String fullMethodBody = String.format(CSHARP_HTTP_CONNECTION_FORMAT, url, methodAndHeaders); // Insert full method body in method format string return String.format(CSHARP_METHOD_FORMAT, methodSignature, fullMethodBody); } @Override public void generateClass(String outputLocation) { StringBuilder methodsSB = new StringBuilder(); for (Function request : this.module.functions) { methodsSB.append(generateFunction(request)); System.out.println("LOG: Function " + request.getFunctionName() + " created"); } String filename = this.module.name; if(this.module.name == null || this.module.name.isEmpty()){ filename = "gargl_output"; System.out.println("WARNING: No module name given, filename defaulting to " + filename); } // File name is currently forced to be the same as module name writeFile(outputLocation + filename + ".cs", String.format(CSHARP_CLASS_FORMAT, filename, methodsSB.toString())); } private String generateMethodAndHeaders(Function function) { StringBuilder sb = new StringBuilder(); // Set request method sb.append("req.Method = \"" + function.getMethod() + "\";\n\n"); // Set request headers sb.append(generateHeaders(function) + "\n"); return sb.toString(); } private String generateHeaders(Function function) { StringBuilder sb = new StringBuilder(); for (Entry<String, String> header : function.getHeaders().entrySet()) { StringBuilder headerSB = new StringBuilder("\"" + header.getKey() + "\", "); headerSB.append(Parameter.processParameter(header.getValue(), function)); // derived from http://stackoverflow.com/a/23070923 // sets headers differently if they're restricted (See CSHARP_RESTRICTED_HEADERS) if(CSHARP_RESTRICTED_HEADERS.contains(header.getKey())) { // of course, connection is another special header... if(header.getKey().equals("Connection") && header.getValue().equals("keep-alive")) { sb.append("req.KeepAlive = true;\n"); } else { sb.append(String.format(CSHARP_HEADER_FORMAT_FIX, header.getKey().replace("-", ""), header.getValue())); } } else { sb.append(String.format(CSHARP_HEADER_FORMAT, headerSB.toString())); } } return sb.toString(); } String generateMethodSignature(Function function) { StringBuilder sb = new StringBuilder(); if (function.getParameters().size() > 0) { for (Parameter param : function.getParameters()) { sb.append("string " + param.getParameterName() + ","); } sb.deleteCharAt(sb.length() - 1); } return String.format(CSHARP_METHOD_SIGNATURE, function.getFunctionName(), sb.toString()); } private String generatePostDataString(Map<String, String> postData) { StringBuilder sb = new StringBuilder(); if (postData != null) { for (Entry<String, String> param : postData.entrySet()) { if (Parameter.isParameter(param.getValue())) { String paramName = Parameter.parameterDecode(param.getValue()); sb.append(param.getKey() + "=\" + " + paramName + " + \"&"); } else { sb.append(param.getKey() + "=" + param.getValue() + "&"); } } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } } else { System.out.println("POST request generated without postData"); } return sb.toString(); } private String generateQueryString(Function function) { StringBuilder sb = new StringBuilder(); for (Entry<String, String> param : function.getQueryString().entrySet()) { if (Parameter.isParameter(param.getValue())) { String paramName = Parameter.parameterDecode(param.getValue()); sb.append(param.getKey() + "=\" + " + paramName + " + \"&"); } else { sb.append(param.getKey() + "=" + param.getValue() + "&"); } } if (sb.length() > 0) { sb.deleteCharAt(sb.length() - 1); } return sb.toString(); } }