Java tutorial
/*! * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2002-2016 Pentaho Corporation.. All rights reserved. */ package org.pentaho.mantle.rebind; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.core.ext.Generator; import com.google.gwt.core.ext.GeneratorContext; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.typeinfo.JClassType; import com.google.gwt.core.ext.typeinfo.JMethod; import com.google.gwt.core.ext.typeinfo.JPackage; import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; import com.google.gwt.event.shared.EventBus; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import org.apache.commons.lang.StringUtils; import org.pentaho.mantle.client.events.EventBusUtil; import java.io.PrintWriter; import java.util.ArrayList; public class EventBusUtilGenerator extends Generator { private String packageName; private String className; private TypeOracle typeOracle; private TreeLogger logger; @Override public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException { this.logger = logger; typeOracle = context.getTypeOracle(); try { // get classType and save instance variables JClassType classType = typeOracle.getType(typeName); packageName = classType.getPackage().getName(); className = classType.getSimpleSourceName() + "Impl"; // Generate class source code generateClass(logger, context); } catch (Exception e) { // record to logger that Map generation threw an exception logger.log(TreeLogger.ERROR, "PropertyMap ERROR!!!", e); } // return the fully qualified name of the class generated return packageName + "." + className; } private void generateClass(TreeLogger logger, GeneratorContext context) { // get print writer that receives the source code PrintWriter printWriter = null; printWriter = context.tryCreate(logger, packageName, className); // print writer if null, source code has ALREADY been generated, return if (printWriter == null) { return; } // init composer, set class properties, create source writer ClassSourceFileComposerFactory composer = null; composer = new ClassSourceFileComposerFactory(packageName, className); composer.addImplementedInterface(EventBusUtil.class.getName()); composer.addImport(GwtEvent.class.getName()); composer.addImport(JavaScriptObject.class.getName()); composer.addImport(EventBus.class.getName()); composer.addImport(HandlerRegistration.class.getName()); SourceWriter sourceWriter = null; sourceWriter = composer.createSourceWriter(context, printWriter); sourceWriter.indent(); // generator constructor source code generateConstructor(sourceWriter); generateMethods(sourceWriter); // close generated class sourceWriter.outdent(); sourceWriter.println("}"); // commit generated class context.commit(logger, printWriter); } private void generateMethods(SourceWriter sourceWriter) { sourceWriter.println( "public native void invokeEventBusJSO(final JavaScriptObject jso, final String parameterJSON)"); sourceWriter.println("/*-{"); sourceWriter.indent(); // unfortunately, we can obtain pairs like {"a":"undefined"} or even {"a":undefined} // the latter will crash the procedure, so let's try to clean up the string // by removing pairs with 'undefined' sourceWriter.println("var tmp = parameterJSON" // replace ("a":undefined) and ("a":"undefined") with empty space + ".replace(/\\\"[\\w]+\\\"\\:[ ]*(\\\")?undefined(\\\")?(,)?/g, '')" // remove doubled commas + ".replace(/,[ ]*,/, ',')" // remove leading and trailing commas + ".replace(/\\{[ ]*,/, '{')" + ".replace(/,[ ]*\\}/, '}');"); sourceWriter.println("var p = JSON.parse(tmp);"); sourceWriter.println("jso.call(this, p)"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println( "public native String getParameterString(final String paramName, final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println( "public native Integer getParameterInteger(final String paramName, final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println( "public native Boolean getParameterBoolean(final String paramName, final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println("public native Float getParameterFloat(final String paramName, " + "final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println( "public native Double getParameterDouble(final String paramName, final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println( "public native Long getParameterLong(final String paramName, final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); sourceWriter.println(); sourceWriter.println("public native Short getParameterShort(final String paramName, " + "final JavaScriptObject parameterMap)"); sourceWriter.println("/*-{"); sourceWriter.indent(); sourceWriter.println("return parameterMap[paramName];"); sourceWriter.outdent(); sourceWriter.println("}-*/;"); // ********************* // FIRE EVENT // ********************* sourceWriter.println(); sourceWriter .println("public void fireEvent(final String eventType, final JavaScriptObject parameterMap) { "); sourceWriter.indent(); try { // find Command implementors ArrayList<JClassType> implementingTypes = new ArrayList<JClassType>(); JPackage pack = typeOracle.getPackage(EventBusUtil.class.getPackage().getName()); JClassType eventSourceType = typeOracle.getType(GwtEvent.class.getName()); for (JClassType type : pack.getTypes()) { if (type.isAssignableTo(eventSourceType)) { implementingTypes.add(type); } } sourceWriter.println("if(false){}"); // placeholder for (JClassType implementingType : implementingTypes) { sourceWriter .println("else if(eventType.equals(\"" + implementingType.getSimpleSourceName() + "\")){"); sourceWriter.indent(); sourceWriter .println(implementingType.getName() + " event = new " + implementingType.getName() + "();"); for (JMethod eventMethod : implementingType.getMethods()) { if (eventMethod.isPublic() && !eventMethod.isStatic() && eventMethod.isConstructor() == null && eventMethod.getName().startsWith("set")) { String propertyName = eventMethod.getName().substring(3); propertyName = propertyName.substring(0, 1).toLowerCase() + propertyName.substring(1); String simpleType = implementingType.getField(propertyName).getType().getSimpleSourceName(); if ("string".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterString(\"" + propertyName + "\", parameterMap));"); } else if ("integer".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterInteger(\"" + propertyName + "\", parameterMap));"); } else if ("float".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterFloat(\"" + propertyName + "\", parameterMap));"); } else if ("double".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterDouble(\"" + propertyName + "\", parameterMap));"); } else if ("long".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterLong(\"" + propertyName + "\", parameterMap));"); } else if ("short".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterShort(\"" + propertyName + "\", parameterMap));"); } else if ("boolean".equalsIgnoreCase(simpleType)) { sourceWriter.println("event." + eventMethod.getName() + "(getParameterBoolean(\"" + propertyName + "\", parameterMap));"); } } } sourceWriter.println("EVENT_BUS.fireEvent(event);"); sourceWriter.outdent(); sourceWriter.println("}"); } } catch (Exception e) { // record to logger that Map generation threw an exception logger.log(TreeLogger.ERROR, "Error generating BindingContext!!!", e); } sourceWriter.outdent(); sourceWriter.println("}"); // ********************* // ADD HANDLER // ********************* sourceWriter.println(); sourceWriter.println( "public HandlerRegistration addHandler(final String eventType, final JavaScriptObject handler) { "); sourceWriter.indent(); try { // find Command implementors JPackage pack = typeOracle.getPackage(EventBusUtil.class.getPackage().getName()); JClassType eventSourceType = typeOracle.getType(GwtEvent.class.getName()); sourceWriter.println("if(false){return null;}"); // placeholder for (JClassType type : pack.getTypes()) { if (type.isAssignableTo(eventSourceType)) { addHandlerElseCondition(sourceWriter, type); } } } catch (Exception e) { // record to logger that Map generation threw an exception logger.log(TreeLogger.ERROR, "Error generating BindingContext!!!", e); } sourceWriter.indent(); sourceWriter.println("return null;"); sourceWriter.outdent(); sourceWriter.println("}"); } private void addHandlerElseCondition(SourceWriter writer, JClassType type) throws NotFoundException { writer.println("else if(eventType.equals(\"" + type.getSimpleSourceName() + "\")){"); writer.indent(); JClassType handlerType = typeOracle .getType(EventBusUtil.class.getPackage().getName() + "." + type.getName() + "Handler"); writer.println("HandlerRegistration handlerRegistration = EVENT_BUS.addHandler(" + type.getName() + ".TYPE, new " + type.getName() + "Handler() {"); writer.indent(); for (JMethod handlerMethod : handlerType.getMethods()) { String parameterJSON = addHandlerParamJson(type); writer.println("public void " + handlerMethod.getName() + "(" + type.getName() + " event) {"); writer.indent(); writer.println("invokeEventBusJSO(handler," + parameterJSON + ");"); writer.outdent(); writer.println("}"); } writer.outdent(); writer.println("});"); writer.indent(); writer.println("return handlerRegistration;"); writer.outdent(); writer.println("}"); } // visible for testing purposes String addHandlerParamJson(JClassType type) { StringBuilder json = new StringBuilder(128); json.append('"').append('{'); JMethod[] methods = type.getMethods(); for (JMethod eventMethod : methods) { if (eventMethod.isPublic() && !eventMethod.isStatic() && (eventMethod.isConstructor() == null) && !"void".equalsIgnoreCase(eventMethod.getReturnType().getSimpleSourceName()) && !eventMethod.getName().equals("getAssociatedType")) { // let's add the property to JSON object String propertyName = StringUtils.uncapitalize(eventMethod.getName().substring(3)); String simpleType = type.getField(propertyName).getType().getSimpleSourceName(); if ("string".equalsIgnoreCase(simpleType)) { json.append( "\\\"" + propertyName + "\\\":\\\"\" + event." + eventMethod.getName() + "() + \"\\\""); } else { json.append("\\\"" + propertyName + "\\\":\" + event." + eventMethod.getName() + "() + \""); } json.append(','); } } int lastIndex = json.lastIndexOf(","); if (lastIndex == -1) { json.append('}'); } else { json.setCharAt(lastIndex, '}'); } return json.append('"').toString(); } private void generateConstructor(SourceWriter sourceWriter) { // start constructor source generation sourceWriter.println("public " + className + "() { "); sourceWriter.indent(); sourceWriter.println("super();"); sourceWriter.outdent(); sourceWriter.println("}"); } @SuppressWarnings("unused") private String boxPrimative(JType type) { if (type.isPrimitive() != null) { JPrimitiveType primative = type.isPrimitive(); return primative.getQualifiedBoxedSourceName(); } else { return type.getQualifiedSourceName(); } } }