001 /* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 * 014 * See the NOTICE file distributed with this work for additional 015 * information regarding copyright ownership. 016 */ 017 018 package com.osbcp.jjsw; 019 020 import java.io.File; 021 import java.io.PrintStream; 022 import java.lang.reflect.Method; 023 import java.util.ArrayList; 024 import java.util.HashMap; 025 import java.util.Iterator; 026 import java.util.List; 027 import java.util.Map; 028 029 /** 030 * Generates JavaScript functions to a JavaScript source file based on JavaScriptFunctions. 031 * 032 * @author <a href=\"mailto:christoffer@christoffer.me\">Christoffer Pettersson</a> 033 * 034 */ 035 036 public final class Generator { 037 038 /** 039 * Private constructor to disallow creating an instance of the class. 040 */ 041 042 private Generator() { 043 } 044 045 /** 046 * Generates JavaScript functions to a JavaScript source file based on JavaScriptFunctions. 047 * 048 * @param classes A list of classes which JavaScript methods that should be exported 049 * @param javaScriptFile File where the generated JavaScript source file that should be written 050 * @param addJavaScriptComments If additional comments should be added in the generated JavaScript source file 051 * @throws Exception If any error occurs 052 */ 053 054 public static void generateTo(final List<Class<?>> classes, final File javaScriptFile, final boolean addJavaScriptComments) throws Exception { 055 056 // Create an empty list for all the found functions 057 Map<String, List<String>> functions = new HashMap<String, List<String>>(); 058 059 // For each class 060 for (final Class<?> klass : classes) { 061 062 // For each declared method 063 for (final Method method : klass.getDeclaredMethods()) { 064 065 /* 066 * Validate 067 */ 068 069 if (!Validator.validateMethod(method)) { 070 continue; 071 } 072 073 // Write debug message 074 System.out.println("Found eligible method '" + method.getName() + "'."); 075 076 // Get the parameter types 077 Class<?>[] types = method.getParameterTypes(); 078 079 // Get instances based on those types 080 Object[] parameters = ClassUtil.getPreDefinedParametersByTypes(types); 081 082 // Invoke the method 083 JavaScript javaScriptFunction = (JavaScript) method.invoke(null, parameters); 084 085 // Get the code based on the objects 086 String rawCode = javaScriptFunction.getCodeRaw(); 087 System.out.println("Raw code is [ " + rawCode + " ]."); 088 089 // Get the injected and escaped code 090 String code = javaScriptFunction.toString(); 091 System.out.println("Injected and escaped code is [ " + code + " ]."); 092 093 /* 094 * Fix the function names 095 */ 096 097 String functionNameJavaScript = StringUtil.md5(rawCode); 098 System.out.println("Function name is '" + functionNameJavaScript + "'."); 099 100 /* 101 * Render JavaScript 102 */ 103 104 // Write the JavaScript file 105 String javaScriptArgumentList = StringUtil.getJavaScriptArgumentList(types.length); 106 107 StringBuilder functionCode = new StringBuilder(); 108 109 if (addJavaScriptComments) { 110 functionCode.append("/*\n"); 111 functionCode.append(" * " + klass.getSimpleName() + "." + method.getName() + "\n"); 112 functionCode.append(" */\n\n"); 113 } 114 functionCode.append(javaScriptFunction.getJavaScriptObjectName() + "." + functionNameJavaScript + " = function(" + javaScriptArgumentList + ") {\n"); 115 functionCode.append(" " + code + "\n"); 116 functionCode.append("}\n"); 117 118 if (functions.containsKey(javaScriptFunction.getJavaScriptObjectName())) { 119 functions.get(javaScriptFunction.getJavaScriptObjectName()).add(functionCode.toString()); 120 } else { 121 List<String> list = new ArrayList<String>(); 122 list.add(functionCode.toString()); 123 functions.put(javaScriptFunction.getJavaScriptObjectName(), list); 124 } 125 126 } 127 128 } 129 130 /* 131 * Print everything out 132 */ 133 134 // Create the file writer for files 135 PrintStream outJavaScript = new PrintStream(javaScriptFile); 136 137 // Loop through all the JavaScript objects 138 if (addJavaScriptComments) { 139 outJavaScript.println("/*"); 140 outJavaScript.println(" * Object structures"); 141 outJavaScript.println(" */\n"); 142 } 143 144 Iterator<String> javaScriptObjectNames = functions.keySet().iterator(); 145 while (javaScriptObjectNames.hasNext()) { 146 147 String javaScriptObjectName = javaScriptObjectNames.next(); 148 149 outJavaScript.println("function " + javaScriptObjectName + "() {"); 150 outJavaScript.println("}\n"); 151 152 } 153 154 // Loop through all the functions and write them to the file 155 for (Map.Entry<String, List<String>> entry : functions.entrySet()) { 156 157 // String javaScriptClassName = entry.getKey(); 158 List<String> functionsCodes = entry.getValue(); 159 160 // outJavaScript.println("function " + javaScriptClassName + "() {"); 161 // outJavaScript.println("}\n"); 162 163 for (String functionCode : functionsCodes) { 164 165 outJavaScript.println(functionCode); 166 167 } 168 169 } 170 171 // Close the writer 172 outJavaScript.close(); 173 174 /* 175 * Print out the done message 176 */ 177 178 System.out.println("Code generation done."); 179 180 } 181 }