package com.eas.script; import com.eas.client.cache.PlatypusFiles; import com.eas.client.forms.components.model.grid.ModelGrid; import com.eas.client.settings.SettingsConstants; import com.eas.util.FileUtils; import com.eas.util.PropertiesUtils; import com.eas.util.StringUtils; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Parameter; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Level; import java.util.logging.Logger; import jdk.nashorn.api.scripting.JSObject; /** * The utility application to convert JavaScript API classes with * * @ScritpFunction annotation to pure JavaScript objects. * * @author vv */ public class Classes2Scripts { public static final String CMD_SWITCHS_PREFIX = "-";//NOI18N public static final String CLASS_PATH_CMD_SWITCH = "source";//NOI18N public static final String DESTINATION_DIRECTORY_CMD_SWITCH = "dest";//NOI18N private static final String JAVA_CLASS_FILE_EXT = ".class";//NOI18N private static final String CONSTRUCTOR_TEMPLATE = getStringResource("constructorTemplate.js");//NOI18N private static final int DEFAULT_IDENTATION_WIDTH = 4; private static final int CONSTRUCTOR_IDENT_LEVEL = 1; private static final String DEPS_TAG = "${Deps}"; private static final String DEPS_RESULTS_TAG = "${DepsResults}"; private static final String NAME_TAG = "${Name}";//NOI18N private static final String JAVA_TYPE_TAG = "${Type}";//NOI18N private static final String PARAMS_TAG = "${Params}";//NOI18N private static final String NULL_PARAMS_TAG = "${NullParams}";//NOI18N private static final String UNWRAPPED_PARAMS_TAG = "${UnwrappedParams}";//NOI18N private static final String MAX_ARGS_TAG = "${MaxArgs}";//NOI18N private static final String BODY_TAG = "${Body}"; private static final String PROPERTIES_TAG = "${Props}";//NOI18N private static final String METHODS_TAG = "${Methods}"; private static final String JSDOC_TAG = "${JsDoc}";//NOI18N private static final String DELEGATE_TAG = "${Delegate}";//NOI18N private static final String DELEGATE_OBJECT = "delegate";//NOI18N private static final String DEFAULT_CONSTRUCTOR_JS_DOC = "" + "/**\n"//NOI18N + " * Generated constructor.\n"//NOI18N + " */";//NOI18N private static final String DEFAULT_PROPERTY_JS_DOC = "" + "/**\n"//NOI18N + " * Generated property jsDoc.\n"//NOI18N + " */";//NOI18N private static final String DEFAULT_METHOD_JS_DOC = "" + "/**\n"//NOI18N + " * Generated method jsDoc.\n"//NOI18N + " */";//NOI18N private static final String JS_DOC_TEMPLATE = "" + "/**\n"//NOI18N + " * %s\n"//NOI18N + " */";//NOI18N private String checkScriptObject(Class clazz, String name) { ScriptObj ann = (ScriptObj) clazz.getAnnotation(ScriptObj.class); if (ann != null && ann.name() != null && !ann.name().isEmpty()) { return ann.name(); } else { return name; } } protected static class MethodedPropBox extends PropertiesUtils.PropBox { public Method method; public String apiName; public MethodedPropBox() { super(); } } private static Classes2Scripts convertor; private final List<File> classPaths = new ArrayList<>(); private File destDirectory; public static void main(String[] args) throws Exception { convertor = new Classes2Scripts(); try { convertor.parseArguments(args); convertor.validate(); convertor.clean(); convertor.run(); System.out.println("Conversion completed."); } catch (Exception ex) { System.out.println("Error: " + ex.getMessage()); Logger.getLogger(Classes2Scripts.class.getName()).log(Level.WARNING, null, ex); } } private void parseArguments(String[] args) throws Exception { int i = 0; while (i < args.length) { if ((CMD_SWITCHS_PREFIX + CLASS_PATH_CMD_SWITCH).equalsIgnoreCase(args[i])) { if (i < args.length - 1) { i += 1; while (i < args.length - 1 && !args[i].startsWith(CMD_SWITCHS_PREFIX)) { classPaths.add(new File(args[i])); i++; } } else { throw new IllegalArgumentException("Source directory argument syntax error"); } } else if ((CMD_SWITCHS_PREFIX + DESTINATION_DIRECTORY_CMD_SWITCH).equalsIgnoreCase(args[i])) { if (i < args.length - 1) { destDirectory = new File(args[i + 1]); i += 2; } else { throw new IllegalArgumentException("Layout directory argument syntax error"); } } else { throw new IllegalArgumentException("Unknown argument: " + args[i]); } } } private void validate() { if (destDirectory == null || !destDirectory.exists()) { throw new IllegalArgumentException("Destination directory does not exists: " + destDirectory); } if (!destDirectory.isDirectory()) { throw new IllegalArgumentException("Destination is not a directory: " + destDirectory); } for (File classPath : classPaths) { if (!classPath.isDirectory() && !isJar(classPath)) { throw new IllegalArgumentException("Class path is not a directory nor a jar file: " + classPath); } } } private static boolean isJar(File f) { return f.isFile() && f.getName().endsWith("jar");//NOI18N } private void clean() throws IOException { if (!destDirectory.isDirectory()) { throw new IllegalArgumentException("Only directory can be used as dest."); // NOI18N } for (File c : destDirectory.listFiles()) { if (c.isDirectory()) { FileUtils.delete(c); } } } private void run() { try { for (File classPath : classPaths) { if (classPath.isDirectory()) { processDirectory(classPath); } else if (isJar(classPath)) { processJar(classPath); } } //createDepsFile(); } catch (IOException | ClassNotFoundException ex) { Logger.getLogger(Classes2Scripts.class.getName()).log(Level.SEVERE, "Conversion error.", ex); } } private void processDirectory(File classPath) throws IOException, ClassNotFoundException { for (File f : classPath.listFiles()) { if (f.isDirectory()) { processDirectory(f); } else if (isJar(f)) { processJar(f); } } } private void processJar(File jarFile) throws IOException, ClassNotFoundException { try (JarFile jar = new JarFile(jarFile)) { Logger.getLogger(Classes2Scripts.class.getName()) .log(Level.FINE, "Processing jar: {0}", new String[]{jarFile.getAbsolutePath()}); URLClassLoader cl = new URLClassLoader(new URL[]{jarFile.toURI().toURL()}, this.getClass().getClassLoader()); List<File> jarApiFiles = new ArrayList<>(); List<String> jarApiClasses = new ArrayList<>(); File subDir = new File(destDirectory, FileNameSupport.getFileName(FileUtils.removeExtension(jarFile.getName()))); Enumeration<JarEntry> e = jar.entries(); while (e.hasMoreElements()) { try { JarEntry jarEntry = e.nextElement(); if (jarEntry.getName().endsWith(JAVA_CLASS_FILE_EXT)) { String className = entryName2ClassName(jarEntry.getName()); Class clazz = Class.forName(className, false, cl); FunctionInfo jsConstructor = getJsConstructorInfo(clazz); if (jsConstructor != null) { String js = getClassJs(clazz); if (js != null) { if (!subDir.exists()) { subDir.mkdir(); } Logger.getLogger(Classes2Scripts.class.getName()) .log(Level.FINE, "\tClass name: {0}", new String[]{className}); File resultFile = new File(subDir, FileNameSupport.getFileName(jsConstructor.name) + PlatypusFiles.JAVASCRIPT_FILE_END); //NOI18N FileUtils.writeString(resultFile, js, SettingsConstants.COMMON_ENCODING); jarApiFiles.add(resultFile); jarApiClasses.add(jsConstructor.name); } } } } catch (NoClassDefFoundError ex) { //NO-OP } } if (!jarApiFiles.isEmpty()) { StringBuilder apiDeps = new StringBuilder(); apiDeps.append("define([\n"); StringBuilder deps = new StringBuilder(); StringBuilder depsRes = new StringBuilder(); StringBuilder moduleItems = new StringBuilder(); for (int i = 0; i < jarApiFiles.size(); i++) { File jarApiFile = jarApiFiles.get(i); String apiClass = jarApiClasses.get(i); if (i == 0) { deps.append(getIndentStr(1)).append(" "); depsRes.append(getIndentStr(1)).append(" "); moduleItems.append(getIndentStr(2)).append(" "); } else { deps.append(getIndentStr(1)).append(", "); depsRes.append(getIndentStr(1)).append(", "); moduleItems.append(getIndentStr(2)).append(", "); } String includeName = jarApiFile.getName(); if (includeName.toLowerCase().endsWith(PlatypusFiles.JAVASCRIPT_FILE_END)) { includeName = includeName.substring(0, includeName.length() - PlatypusFiles.JAVASCRIPT_FILE_END.length()); } deps.append("'./").append(includeName).append("'\n"); depsRes.append(apiClass).append("\n"); moduleItems.append(apiClass).append(": ").append(apiClass).append("\n"); } apiDeps.append(deps).append("]").append(", function(\n"); apiDeps.append(depsRes).append(getIndentStr(1)).append("){\n").append(getIndentStr(1)).append("return {\n"); apiDeps.append(moduleItems).append(getIndentStr(1)).append("};\n"); apiDeps.append("});\n"); File depsFile = Paths.get(subDir.toURI()).resolve("index.js").toFile(); FileUtils.writeString(depsFile, apiDeps.toString(), SettingsConstants.COMMON_ENCODING); } } } protected String getClassJs(Class clazz) { FunctionInfo ci = getJsConstructorInfo(clazz); if (ci.javaClassName.contains("$")) { Logger.getLogger(Classes2Scripts.class.getName()).log(Level.WARNING, "Inner class: {0}", ci.javaClassName); return null; } if (Modifier.isAbstract(clazz.getModifiers())) { Logger.getLogger(Classes2Scripts.class.getName()).log(Level.WARNING, "Abstract class: {0}", ci.javaClassName); return null; } if (!checkForHasPublished(clazz)) { Logger.getLogger(Classes2Scripts.class.getName()).log(Level.WARNING, "HasPublished iterface is not implemented: {0}", clazz.getName()); return null; } /// List<Method> methods = new ArrayList<>(); Map<String, MethodedPropBox> props = new HashMap<>(); for (Method method : clazz.getMethods()) { if (method.isAnnotationPresent(ScriptFunction.class)) { ScriptFunction propAnn = method.getAnnotation(ScriptFunction.class); if (PropertiesUtils.isBeanPatternMethod(method)) { String propName = PropertiesUtils.getPropertyName(method.getName()); MethodedPropBox pb = props.get(propName); if (pb == null) { pb = new MethodedPropBox(); pb.name = propName; if (propAnn.name() != null && !propAnn.name().isEmpty()) { pb.apiName = propAnn.name(); } else { pb.apiName = propName; } pb.method = method; props.put(pb.name, pb); } PropertiesUtils.setPropertyAccessStatus(pb, method.getName()); PropertiesUtils.setPropertyReturnType(pb, method); if (pb.jsDoc == null || pb.jsDoc.isEmpty()) { pb.jsDoc = propAnn.jsDoc(); } } else { methods.add(method); } } } // if (ci.javaClassName.startsWith("com.eas.client.forms.components") || ci.javaClassName.startsWith("com.eas.client.forms.containers") || ci.javaClassName.startsWith("com.eas.client.forms.menu")) { if (ci.javaClassName.startsWith("com.eas.client.forms.components.model.grid.header")) { ci.jsDeps += ", 'common-utils/color', 'common-utils/cursor', 'common-utils/font', './cell-render-event'"; ci.jsDepsResults += ", Color, Cursor, Font, RenderEvent"; } else { ci.jsDeps += ", 'common-utils/color', 'common-utils/cursor', 'common-utils/font', './action-event', './cell-render-event', './component-event', './focus-event', './item-event', './key-event', './value-change-event'"; ci.jsDepsResults += ", Color, Cursor, Font, ActionEvent, RenderEvent, ComponentEvent, FocusEvent, ItemEvent, KeyEvent, ValueChangeEvent"; if (ci.javaClassName.startsWith("com.eas.client.forms.containers") || ci.javaClassName.startsWith("com.eas.client.forms.menu.MenuBar") || ci.javaClassName.startsWith("com.eas.client.forms.menu.Menu") || ci.javaClassName.startsWith("com.eas.client.forms.menu.PopupMenu")) { ci.jsDeps += ", './container-event'"; ci.jsDepsResults += ", ContainerEvent"; } if (!ci.javaClassName.equals("com.eas.client.forms.menu.PopupMenu")) { ci.jsDeps += ", './popup-menu'"; ci.jsDepsResults += ", PopupMenu"; } } } if (ModelGrid.class.getName().equals(ci.javaClassName)) { ci.jsDeps += ", 'grid/cell-data', './service-grid-column', './check-grid-column', './radio-grid-column', './model-check-box', './model-combo', './model-date', './model-formatted-field', './model-grid-column', './model-spin', './model-text-area'"; ci.jsDepsResults += ", CellData, RenderEvent, ItemEvent, ServiceGridColumn, CheckGridColumn, RadioGridColumn, ModelCheckBox, ModelCombo, ModelDate, ModelFormattedField, ModelGridColumn, ModelSpin, ModelTextArea"; } String js = CONSTRUCTOR_TEMPLATE .replace(DEPS_TAG, ci.jsDeps) .replace(DEPS_RESULTS_TAG, ci.jsDepsResults) .replace(JAVA_TYPE_TAG, ci.javaClassName) .replace(JSDOC_TAG, getConstructorJsDoc(ci)) .replace(NAME_TAG, checkScriptObject(clazz, ci.name)) .replace(NULL_PARAMS_TAG, ci.getNullParamsStr()) .replace(PARAMS_TAG, ci.getParamsStr()) .replace(DELEGATE_TAG, DELEGATE_OBJECT) .replace(UNWRAPPED_PARAMS_TAG, ci.getUnwrappedParamsStr(3)) .replace(MAX_ARGS_TAG, Integer.toString(ci.params.length)) .replace(PROPERTIES_TAG, getPropsPart(clazz, ci, props.values(), CONSTRUCTOR_IDENT_LEVEL + 1)) .replace(METHODS_TAG, getMethodsPart(clazz, ci, methods, CONSTRUCTOR_IDENT_LEVEL)); js = js.replace(BODY_TAG, ""); return js; } private static String pathRootDir(String path) { String[] pathElements = path.split("/"); if (pathElements.length > 0) { return pathElements[0]; } else { return null; } } private static String getRelativePath(File base, File file) { Path pathAbsolute = file.toPath(); Path pathBase = base.toPath(); return pathBase.relativize(pathAbsolute).toString().replace("\\", "/"); } private static boolean checkForHasPublished(Class clazz) { return HasPublished.class.isAssignableFrom(clazz); } private static String getConstructorJsDoc(FunctionInfo ci) { return addIndent(appendLine2JsDoc(formJsDoc(ci.jsDoc), "@constructor " + ci.name + " " + ci.name), CONSTRUCTOR_IDENT_LEVEL); } private static String getIndentStr(int ident) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < DEFAULT_IDENTATION_WIDTH * ident; i++) { sb.append(" ");//NOI18N } return sb.toString(); } private static String entryName2ClassName(String entryName) { return entryName.substring(0, entryName.length() - JAVA_CLASS_FILE_EXT.length()).replace("/", ".");//NOI18N } private static String getStringResource(String resName) { try { return FileUtils.readString(new File(Classes2Scripts.class.getResource(resName).toURI()), SettingsConstants.COMMON_ENCODING);//NOI18N } catch (IOException | URISyntaxException ex) { throw new RuntimeException(ex); } } private FunctionInfo getJsConstructorInfo(Class clazz) { try { for (Constructor constr : clazz.getConstructors()) { if (constr.isAnnotationPresent(ScriptFunction.class)) { return getConstructorInfo(clazz.getName(), clazz.getSimpleName(), constr); } } for (Method method : clazz.getMethods()) { if (method.isAnnotationPresent(ScriptFunction.class)) { return getSimpleConstructorInfo(clazz.getName(), clazz.getSimpleName()); } } } catch (Exception ex) { Logger.getLogger(Classes2Scripts.class.getName()).log(Level.SEVERE, ex.getMessage()); } return null; } private FunctionInfo getSimpleConstructorInfo(String javaType, String name) { FunctionInfo fi = new FunctionInfo(); fi.javaClassName = javaType; fi.name = name; fi.jsDoc = DEFAULT_CONSTRUCTOR_JS_DOC; return fi; } private FunctionInfo getConstructorInfo(String javaType, String defaultName, Executable ae) { FunctionInfo fi = getFunctionInfo(defaultName, ae); fi.javaClassName = javaType; return fi; } private FunctionInfo getFunctionInfo(String defaultName, Executable ae) { FunctionInfo fi = new FunctionInfo(); ScriptFunction sf = (ScriptFunction) ae.getAnnotation(ScriptFunction.class); fi.name = sf.name().isEmpty() ? defaultName : sf.name(); fi.apiName = sf.name(); fi.jsDoc = formJsDoc(sf.jsDoc()); fi.params = new String[sf.params().length]; fi.nativeParams = ae.getParameters(); System.arraycopy(sf.params(), 0, fi.params, 0, sf.params().length); return fi; } private String getPropertyPart(String namespace, MethodedPropBox property, int ident) { StringBuilder sb = new StringBuilder(); int i = ident; String commonIndent = getIndentStr(i); String apiPropName = property.name; if (property.apiName != null && !property.apiName.isEmpty()) { apiPropName = property.apiName; } if (property.jsDoc != null && !property.jsDoc.isEmpty()) { String[] jsDocLines = property.jsDoc.split("\n"); for (String jsDocLine : jsDocLines) { sb.append(commonIndent).append(jsDocLine).append("\n"); } } String propValueSample; if (property.typeName != null) { switch (property.typeName) { case "String": propValueSample = "''"; break; case "Boolean": propValueSample = "true"; break; case "Number": propValueSample = "0"; break; default: propValueSample = "new Object()"; break; } } else { propValueSample = "new Object()"; } sb.append(commonIndent).append("this.").append(apiPropName).append(" = ").append(propValueSample).append(";").append("\n"); sb.append(commonIndent).append("Object.defineProperty(").append("this, \"").append(apiPropName).append("\", {\n"); sb.append(getIndentStr(++i)); assert property.readable; sb.append("get: function() {\n"); sb.append(getIndentStr(++i)); sb.append("var value = ").append(DELEGATE_OBJECT).append(".").append(property.name).append(";\n"); sb.append(getIndentStr(i)); if (JSObject.class.isAssignableFrom(property.method.getReturnType())) { sb.append("return value;\n"); } else { sb.append("return B.boxAsJs(value);\n"); } sb.append(getIndentStr(--i)); sb.append("}"); if (property.writeable) { sb.append(",\n"); sb.append(getIndentStr(i)); sb.append("set: function(aValue) {\n"); sb.append(getIndentStr(++i)); sb.append(DELEGATE_OBJECT).append(".").append(property.name); if (JSObject.class.isAssignableFrom(property.method.getReturnType())) { sb.append(" = aValue;\n"); } else { sb.append(" = B.boxAsJava(aValue);\n"); } sb.append(getIndentStr(--i)); sb.append("}\n"); } else { sb.append("\n"); } sb.append(getIndentStr(--i)); sb.append("});\n"); /* TODO: sb.append(getIndentStr(i)).append("if(!P.").append(namespace).append("){\n"); sb.append(getPropertyJsDoc(namespace, property, ++i)).append("\n"); sb.append(getIndentStr(i)).append("P.").append(namespace).append(".prototype.").append(apiPropName).append(" = ").append(getDefaultLiteralOfType(property.typeName)).append(";\n"); sb.append(getIndentStr(--i)).append("}"); */ return sb.toString(); } /* private String getDefaultLiteralOfType(String aTypeName) { if ("Number".equals(aTypeName)) { return "0"; } else if ("Date".equals(aTypeName)) { return "new Date()"; } else if (aTypeName != null && aTypeName.startsWith("[]")) { return aTypeName; } else if ("Boolean".equals(aTypeName)) { return "true"; } else if ("String".equals(aTypeName)) { return "''"; } else { return "{}"; } } */ private String getMethodPart(String namespace, Method method, int indent) { FunctionInfo fi = getFunctionInfo(method.getName(), method); StringBuilder sb = new StringBuilder(); int i = indent; String methodName = fi.name; if (fi.apiName != null && !fi.apiName.isEmpty()) { methodName = fi.apiName; } sb.append(getMethodJsDoc(namespace, methodName, fi.jsDoc, i)).append("\n"); sb.append(getIndentStr(i)); sb.append(namespace).append(".prototype.").append(methodName).append(" = ") .append("function("); StringBuilder paramsInCall = new StringBuilder(); StringBuilder formalParams = new StringBuilder(); String delimiter = ""; ScriptFunction methodAnnotation = method.getAnnotation(ScriptFunction.class); Parameter[] methodParams = method.getParameters(); for (int p = 0; p < methodParams.length; p++) { Parameter param = methodParams[p]; String pName = param.getName(); if (methodAnnotation != null && p < methodAnnotation.params().length) { pName = methodAnnotation.params()[p]; } formalParams.append(delimiter).append(pName); paramsInCall.append(delimiter).append("B.boxAsJava(").append(pName).append(")"); if (delimiter.isEmpty()) { delimiter = ", "; } } sb.append(formalParams); sb.append(") {\n"); sb.append(getIndentStr(++i)); sb.append("var ").append(DELEGATE_OBJECT).append(" = this.unwrap();\n"); sb.append(getIndentStr(i)); sb.append("var value = ") .append(DELEGATE_OBJECT) .append(".") .append(method.getName()) .append("(") .append(paramsInCall) .append(");\n"); sb.append(getIndentStr(i)); sb.append("return B.boxAsJs(value);\n"); sb.append(getIndentStr(--i)); sb.append("};\n"); return sb.toString(); } private String getPropertyJsDoc(String namespace, MethodedPropBox property, int indent) { String jsDoc = property.jsDoc == null || property.jsDoc.isEmpty() ? DEFAULT_PROPERTY_JS_DOC : property.jsDoc; jsDoc = formJsDoc(jsDoc); jsDoc = appendLine2JsDoc(jsDoc, "@property " + property.name); jsDoc = appendLine2JsDoc(jsDoc, "@memberOf " + namespace); return addIndent(jsDoc, indent); } private String getMethodJsDoc(String namespace, String methodName, String str, int ident) { String jsDoc = str == null || str.isEmpty() ? DEFAULT_METHOD_JS_DOC : str; jsDoc = formJsDoc(jsDoc); jsDoc = appendLine2JsDoc(jsDoc, "@method " + methodName); jsDoc = appendLine2JsDoc(jsDoc, "@memberOf " + namespace); return addIndent(jsDoc, ident); } private static String formJsDoc(String jsDoc) { if (!jsDoc.trim().startsWith("/**")) {//NOI18N return String.format(JS_DOC_TEMPLATE, jsDoc); } else { String[] lines = jsDoc.split("\n"); for (int i = 1; i < lines.length; i++) { lines[i] = " " + lines[i].trim(); } return StringUtils.join("\n", lines); } } private static String addIndent(String str, int indent) { StringBuilder sb = new StringBuilder(); String[] lines = str.split("\n");//NOI18N for (int i = 0; i < lines.length; i++) { sb.append(getIndentStr(indent)); sb.append(lines[i]); if (i < lines.length - 1) { sb.append("\n"); } } return sb.toString(); } private static String appendLine2JsDoc(String jsDoc, String line) { List<String> jsDocLines = new ArrayList(Arrays.asList(jsDoc.split("\n")));//NOI18N jsDocLines.add(jsDocLines.size() - 1, " * " + line);//NOI18N StringBuilder sb = new StringBuilder(); for (int i = 0; i < jsDocLines.size(); i++) { sb.append(jsDocLines.get(i)); if (i < jsDocLines.size() - 1) { sb.append("\n");//NOI18N } } return sb.toString(); } private String getPropsPart(Class clazz, FunctionInfo ci, Collection<MethodedPropBox> props, int ident) { StringBuilder sb = new StringBuilder(); for (MethodedPropBox property : props) { sb.append(getPropertyPart(checkScriptObject(clazz, ci.name), property, ident)) .append("\n");//NOI18N } return sb.toString(); } private String getMethodsPart(Class clazz, FunctionInfo ci, Collection<Method> methods, int ident) { StringBuilder sb = new StringBuilder(); Set<String> generatedMethods = new HashSet<>(); for (Method method : methods) { if (generatedMethods.contains(method.getName())) { throw new IllegalStateException("API Method \"" + method + "\" is duplicated."); } sb.append(getMethodPart(checkScriptObject(clazz, ci.name), method, ident)); sb.append("\n");//NOI18N generatedMethods.add(method.getName()); } if ("com.eas.client.forms.Form".equals(clazz.getName())) { sb.append("" + " var FormClass = Java.type(\"com.eas.client.forms.Form\");\n" + " Object.defineProperty(Form, 'shown', {\n" + " get: function () {\n" + " var nativeArray = FormClass.getShownForms();\n" + " var res = [];\n" + " for (var i = 0; i < nativeArray.length; i++)\n" + " res[res.length] = nativeArray[i].getPublished();\n" + " return res;\n" + " }\n" + " });\n" + "\n" + " Object.defineProperty(Form, 'getShownForm', {\n" + " value: function (aName) {\n" + " var shownForm = FormClass.getShownForm(aName);\n" + " return shownForm !== null ? shownForm.getPublished() : null;\n" + " }\n" + " });\n" + "\n" + " Object.defineProperty(Form, 'onChange', {\n" + " get: function () {\n" + " return FormClass.getOnChange();\n" + " },\n" + " set: function (aValue) {\n" + " FormClass.setOnChange(aValue);\n" + " }\n" + " });\n" + "\n" + ""); } else if ("com.eas.gui.ScriptColor".equals(clazz.getName())) { sb.append("" + " Object.defineProperty(Color, \"black\", {value: new Color(0, 0, 0)});\n" + " Object.defineProperty(Color, \"BLACK\", {value: new Color(0, 0, 0)});\n" + " Object.defineProperty(Color, \"blue\", {value: new Color(0, 0, 0xff)});\n" + " Object.defineProperty(Color, \"BLUE\", {value: new Color(0, 0, 0xff)});\n" + " Object.defineProperty(Color, \"cyan\", {value: new Color(0, 0xff, 0xff)});\n" + " Object.defineProperty(Color, \"CYAN\", {value: new Color(0, 0xff, 0xff)});\n" + " Object.defineProperty(Color, \"DARK_GRAY\", {value: new Color(0x40, 0x40, 0x40)});\n" + " Object.defineProperty(Color, \"darkGray\", {value: new Color(0x40, 0x40, 0x40)});\n" + " Object.defineProperty(Color, \"gray\", {value: new Color(0x80, 0x80, 0x80)});\n" + " Object.defineProperty(Color, \"GRAY\", {value: new Color(0x80, 0x80, 0x80)});\n" + " Object.defineProperty(Color, \"green\", {value: new Color(0, 0xff, 0)});\n" + " Object.defineProperty(Color, \"GREEN\", {value: new Color(0, 0xff, 0)});\n" + " Object.defineProperty(Color, \"LIGHT_GRAY\", {value: new Color(0xC0, 0xC0, 0xC0)});\n" + " Object.defineProperty(Color, \"lightGray\", {value: new Color(0xC0, 0xC0, 0xC0)});\n" + " Object.defineProperty(Color, \"magenta\", {value: new Color(0xff, 0, 0xff)});\n" + " Object.defineProperty(Color, \"MAGENTA\", {value: new Color(0xff, 0, 0xff)});\n" + " Object.defineProperty(Color, \"orange\", {value: new Color(0xff, 0xC8, 0)});\n" + " Object.defineProperty(Color, \"ORANGE\", {value: new Color(0xff, 0xC8, 0)});\n" + " Object.defineProperty(Color, \"pink\", {value: new Color(0xFF, 0xAF, 0xAF)});\n" + " Object.defineProperty(Color, \"PINK\", {value: new Color(0xFF, 0xAF, 0xAF)});\n" + " Object.defineProperty(Color, \"red\", {value: new Color(0xFF, 0, 0)});\n" + " Object.defineProperty(Color, \"RED\", {value: new Color(0xFF, 0, 0)});\n" + " Object.defineProperty(Color, \"white\", {value: new Color(0xFF, 0xff, 0xff)});\n" + " Object.defineProperty(Color, \"WHITE\", {value: new Color(0xFF, 0xff, 0xff)});\n" + " Object.defineProperty(Color, \"yellow\", {value: new Color(0xFF, 0xff, 0)});\n" + " Object.defineProperty(Color, \"YELLOW\", {value: new Color(0xFF, 0xff, 0)});\n" + ""); } else if ("com.eas.gui.Cursor".equals(clazz.getName())) { sb.append("" + " Object.defineProperty(Cursor, \"CROSSHAIR\", {value: new Cursor(1)});\n" + " Object.defineProperty(Cursor, \"DEFAULT\", {value: new Cursor(0)});\n" + " Object.defineProperty(Cursor, \"AUTO\", {value: new Cursor(0)});\n" + " Object.defineProperty(Cursor, \"E_RESIZE\", {value: new Cursor(11)});\n" + " Object.defineProperty(Cursor, \"HAND\", {value: new Cursor(12)});\n" + " Object.defineProperty(Cursor, \"MOVE\", {value: new Cursor(13)});\n" + " Object.defineProperty(Cursor, \"NE_RESIZE\", {value: new Cursor(7)});\n" + " Object.defineProperty(Cursor, \"NW_RESIZE\", {value: new Cursor(6)});\n" + " Object.defineProperty(Cursor, \"N_RESIZE\", {value: new Cursor(8)});\n" + " Object.defineProperty(Cursor, \"SE_RESIZE\", {value: new Cursor(5)});\n" + " Object.defineProperty(Cursor, \"SW_RESIZE\", {value: new Cursor(4)});\n" + " Object.defineProperty(Cursor, \"S_RESIZE\", {value: new Cursor(9)});\n" + " Object.defineProperty(Cursor, \"TEXT\", {value: new Cursor(2)});\n" + " Object.defineProperty(Cursor, \"WAIT\", {value: new Cursor(3)});\n" + " Object.defineProperty(Cursor, \"W_RESIZE\", {value: new Cursor(10)});\n" + ""); } return sb.toString(); } protected static class FunctionInfo { public FunctionInfo() { jsDoc = "";//NOI18N params = new String[]{}; nativeParams = new Parameter[]{}; } public String name; public String apiName; public String javaClassName; public String jsDeps = "'boxing'"; public String jsDepsResults = "B"; public String[] params; public Parameter[] nativeParams; public String jsDoc; public String getNullParamsStr() { if (params.length == 0) { return "";//NOI18N } StringBuilder paramsSb = new StringBuilder(); for (String param : params) { paramsSb.append("null, ");//NOI18N } return paramsSb.toString(); } public String getParamsStr() { StringBuilder paramsSb = new StringBuilder(); for (int i = 0; i < params.length; i++) { paramsSb.append(params[i]); if (i < params.length - 1) { paramsSb.append(", ");//NOI18N } } return paramsSb.toString(); } public String getUnwrappedParamsStr(int indent) { StringBuilder argsSb = new StringBuilder(); if (params.length != nativeParams.length) { throw new IllegalStateException("@ScriptFunction annotation 'params' parameter is invalid. Constructor of " + javaClassName); } for (int argsCount = params.length; argsCount >= 0; argsCount--) { if (argsCount > 0) { argsSb.append("arguments.length === ").append(argsCount).append(" ? "); } StringBuilder paramsSb = new StringBuilder(); paramsSb.append("new javaClass("); for (int i = 0; i < argsCount; i++) { paramsSb.append("B.boxAsJava(").append(params[i]).append(")"); if (i < argsCount - 1) { paramsSb.append(", ");//NOI18N } } paramsSb.append(")"); argsSb.append(paramsSb); if (argsCount > 0) { argsSb.append("\n").append(getIndentStr(indent)).append(": "); } } return argsSb.toString(); } } }