| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.user.rebind; |
| |
| 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.JParameter; |
| import com.google.gwt.core.ext.typeinfo.JType; |
| import com.google.gwt.i18n.rebind.AbstractResource; |
| import com.google.gwt.i18n.rebind.AbstractResource.MissingResourceException; |
| import com.google.gwt.i18n.shared.GwtLocale; |
| |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Set; |
| |
| /** |
| * Abstract functionality needed to create classes needed to supply generators. |
| */ |
| public abstract class AbstractGeneratorClassCreator extends |
| AbstractSourceCreator { |
| |
| /** |
| * Returns all interface methods associated with the given type. |
| * |
| * @param type associated type |
| * @return interface methods. |
| */ |
| public static JMethod[] getAllInterfaceMethods(JClassType type) { |
| Map<String, JMethod> methods = new HashMap<String, JMethod>(); |
| getAllInterfaceMethodsAux(type, methods); |
| return methods.values().toArray(new JMethod[methods.size()]); |
| } |
| |
| private static void getAllInterfaceMethodsAux(JClassType type, |
| Map<String, JMethod> m) { |
| if (type.isInterface() != null) { |
| JMethod[] methods = type.getMethods(); |
| for (int i = 0; i < methods.length; i++) { |
| String s = uniqueMethodKey(methods[i]); |
| if (m.get(s) == null) { |
| m.put(s, methods[i]); |
| } |
| } |
| JClassType[] supers = type.getImplementedInterfaces(); |
| for (int i = 0; i < supers.length; i++) { |
| getAllInterfaceMethodsAux(supers[i], m); |
| } |
| } |
| } |
| |
| private static String uniqueMethodKey(JMethod method) { |
| String name = method.getName(); |
| name += "("; |
| JParameter[] m = method.getParameters(); |
| for (int i = 0; i < m.length; i++) { |
| name += m[i].getType() + " "; |
| } |
| name += ")"; |
| return name; |
| } |
| |
| /** |
| * List of registered method factories associated with <code>Constant</code> |
| * method implementations. |
| */ |
| protected Map<JType, AbstractMethodCreator> methodFactories = new HashMap<JType, AbstractMethodCreator>(); |
| |
| /** |
| * The interface the generator is conforming to. |
| */ |
| JClassType targetClass; |
| |
| private final SourceWriter writer; |
| |
| /** |
| * Creates a new class creator, supplies a place to write the class, the |
| * interface to conform to, and the new name. |
| * |
| * @param writer writer |
| * @param targetClass class name |
| */ |
| public AbstractGeneratorClassCreator(SourceWriter writer, |
| JClassType targetClass) { |
| this.targetClass = targetClass; |
| this.writer = writer; |
| } |
| |
| /** |
| * Emits the new class. |
| * |
| * @param logger |
| * @param locale |
| * @throws UnableToCompleteException |
| */ |
| public void emitClass(TreeLogger logger, GwtLocale locale) |
| throws UnableToCompleteException { |
| logger = branch(logger, branchMessage()); |
| classPrologue(); |
| emitMethods(logger, targetClass, locale); |
| classEpilog(); |
| getWriter().println("}"); |
| } |
| |
| public JClassType getTarget() { |
| return targetClass; |
| } |
| |
| public UnableToCompleteException logMissingResource(TreeLogger logger, String during, |
| MissingResourceException e) { |
| String msg = "No resource found for key '" + e.getKey() + "'"; |
| if (during != null) { |
| msg += " while " + during; |
| } |
| logger.log(TreeLogger.ERROR, msg, e); |
| TreeLogger searchedBranch = logger.branch(TreeLogger.WARN, "Searched the following resources:", |
| null); |
| for (AbstractResource resource : e.getSearchedResources()) { |
| TreeLogger resBranch = searchedBranch.branch(TreeLogger.WARN, resource.toString(), null); |
| Set<String> keys = resource.keySet(); |
| TreeLogger keyBranch = resBranch.branch(TreeLogger.INFO, "List of keys found", null); |
| for (String key : keys) { |
| keyBranch.log(TreeLogger.INFO, key, null); |
| } |
| } |
| return new UnableToCompleteException(); |
| } |
| |
| /** |
| * Registers a method creator. |
| * |
| * @param returnType return type that this creator handles. |
| * @param creator creator to register |
| */ |
| public void register(JType returnType, AbstractMethodCreator creator) { |
| // TODO: Hacked to get the gwt-trunk for 1.5 building. |
| methodFactories.put(returnType.getErasedType(), creator); |
| } |
| |
| /** |
| * Returns the standard message when constructing a branch. |
| * |
| * @return branch message |
| */ |
| protected String branchMessage() { |
| return "Constructing " + targetClass; |
| } |
| |
| /** |
| * Entry point for subclass cleanup code. |
| */ |
| protected void classEpilog() { |
| } |
| |
| /** |
| * Entry point for subclass setup code. |
| */ |
| protected void classPrologue() { |
| } |
| |
| /** |
| * Emit method body, arguments are arg1...argN. |
| * |
| * @param logger TreeLogger for logging |
| * @param method method to generate |
| * @param locale locale for this generation |
| * @throws UnableToCompleteException |
| */ |
| protected abstract void emitMethodBody(TreeLogger logger, JMethod method, |
| GwtLocale locale) throws UnableToCompleteException; |
| |
| /** |
| * Gets the method creator associated with the return type of the method. |
| * |
| * @param logger |
| * @param method method to create |
| * @return the method creator |
| * @throws UnableToCompleteException |
| */ |
| protected AbstractMethodCreator getMethodCreator(TreeLogger logger, |
| JMethod method) throws UnableToCompleteException { |
| JType type = method.getReturnType(); |
| |
| // TODO make the build work. This is not correct. |
| type = type.getErasedType(); |
| |
| AbstractMethodCreator methodCreator = methodFactories.get(type); |
| if (methodCreator == null) { |
| String msg = "No current method creator exists for " + method |
| + " only methods with return types of "; |
| Iterator<JType> iter = this.methodFactories.keySet().iterator(); |
| while (iter.hasNext()) { |
| msg += iter.next().getSimpleSourceName(); |
| if (iter.hasNext()) { |
| msg += ", "; |
| } |
| } |
| msg += " can be created"; |
| throw error(logger, msg); |
| } |
| return methodCreator; |
| } |
| |
| /** |
| * Gets the associated writer. |
| * |
| * @return writer |
| */ |
| protected SourceWriter getWriter() { |
| return writer; |
| } |
| |
| private void emitMethods(TreeLogger logger, JClassType cur, GwtLocale locale) |
| throws UnableToCompleteException { |
| JMethod[] x = getAllInterfaceMethods(cur); |
| for (int i = 0; i < x.length; i++) { |
| genMethod(logger, x[i], locale); |
| getWriter().println(); |
| } |
| } |
| |
| /** |
| * Generates a method declaration for the given method. |
| * |
| * @param method method to generate |
| * @param locale |
| * @throws UnableToCompleteException |
| */ |
| private void genMethod(TreeLogger logger, JMethod method, GwtLocale locale) |
| throws UnableToCompleteException { |
| String name = method.getName(); |
| String returnType = method.getReturnType().getParameterizedQualifiedSourceName(); |
| getWriter().print("public " + returnType + " " + name + "("); |
| JParameter[] params = method.getParameters(); |
| for (int i = 0; i < params.length; i++) { |
| if (i != 0) { |
| getWriter().print(","); |
| } |
| getWriter().print( |
| params[i].getType().getParameterizedQualifiedSourceName() + " arg" |
| + (i)); |
| } |
| getWriter().println(") {"); |
| getWriter().indent(); |
| String methodName = method.getName(); |
| TreeLogger branch = branch(logger, "Generating method body for " |
| + methodName + "()"); |
| try { |
| emitMethodBody(branch, method, locale); |
| } catch (MissingResourceException e) { |
| throw logMissingResource(branch, null, e); |
| } |
| getWriter().outdent(); |
| getWriter().println("}"); |
| } |
| } |