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    }