001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.rebind;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.core.ext.UnableToCompleteException;
020: import com.google.gwt.core.ext.typeinfo.JClassType;
021: import com.google.gwt.core.ext.typeinfo.JMethod;
022: import com.google.gwt.core.ext.typeinfo.JParameter;
023: import com.google.gwt.core.ext.typeinfo.JType;
024:
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.Map;
028:
029: /**
030: * Abstract functionality needed to create classes needed to supply generators.
031: */
032: public abstract class AbstractGeneratorClassCreator extends
033: AbstractSourceCreator {
034:
035: /**
036: * Returns all interface methods associated with the given type.
037: *
038: * @param type associated type
039: * @return interface methods.
040: */
041: public static JMethod[] getAllInterfaceMethods(JClassType type) {
042: Map<String, JMethod> methods = new HashMap<String, JMethod>();
043: getAllInterfaceMethodsAux(type, methods);
044: return methods.values().toArray(new JMethod[methods.size()]);
045: }
046:
047: private static void getAllInterfaceMethodsAux(JClassType type,
048: Map<String, JMethod> m) {
049: if (type.isInterface() != null) {
050: JMethod[] methods = type.getMethods();
051: for (int i = 0; i < methods.length; i++) {
052: String s = uniqueMethodKey(methods[i]);
053: if (m.get(s) == null) {
054: m.put(s, methods[i]);
055: }
056: }
057: JClassType[] super s = type.getImplementedInterfaces();
058: for (int i = 0; i < super s.length; i++) {
059: getAllInterfaceMethodsAux(super s[i], m);
060: }
061: }
062: }
063:
064: private static String uniqueMethodKey(JMethod method) {
065: String name = method.getName();
066: name += "(";
067: JParameter[] m = method.getParameters();
068: for (int i = 0; i < m.length; i++) {
069: name += m[i].getType() + " ";
070: }
071: name += ")";
072: return name;
073: }
074:
075: /**
076: * List of registered method factories associated with <code>Constant</code>
077: * method implementations.
078: */
079: protected Map<JType, AbstractMethodCreator> methodFactories = new HashMap<JType, AbstractMethodCreator>();
080:
081: /**
082: * The interface the generator is conforming to.
083: */
084: JClassType targetClass;
085:
086: private final SourceWriter writer;
087:
088: /**
089: * Creates a new class creator, supplies a place to write the class, the
090: * interface to conform to, and the new name.
091: *
092: * @param writer writer
093: * @param targetClass class name
094: */
095: public AbstractGeneratorClassCreator(SourceWriter writer,
096: JClassType targetClass) {
097: this .targetClass = targetClass;
098: this .writer = writer;
099: }
100:
101: /**
102: * Emits the new class.
103: *
104: * @param logger
105: * @throws UnableToCompleteException
106: */
107: public void emitClass(TreeLogger logger)
108: throws UnableToCompleteException {
109: logger = branch(logger, branchMessage());
110: classPrologue();
111: emitMethods(logger, targetClass);
112: classEpilog();
113: getWriter().println("}");
114: }
115:
116: public JClassType getTarget() {
117: return targetClass;
118: }
119:
120: /**
121: * Registers a method creator.
122: *
123: * @param returnType return type that this creator handles.
124: * @param creator creator to register
125: */
126: public void register(JType returnType, AbstractMethodCreator creator) {
127: // TODO: Hacked to get the gwt-trunk for 1.5 building.
128: methodFactories.put(returnType.getErasedType(), creator);
129: }
130:
131: /**
132: * Returns the standard message when constructing a branch.
133: *
134: * @return branch message
135: */
136: protected String branchMessage() {
137: return "Constructing " + targetClass;
138: }
139:
140: /**
141: * Entry point for subclass cleanup code.
142: */
143: protected void classEpilog() {
144: }
145:
146: /**
147: * Entry point for subclass setup code.
148: */
149: protected void classPrologue() {
150: }
151:
152: /**
153: * Emit method body, arguments are arg1...argN.
154: *
155: * @param logger TODO
156: * @param method method to generate
157: * @throws UnableToCompleteException
158: */
159: protected abstract void emitMethodBody(TreeLogger logger,
160: JMethod method) throws UnableToCompleteException;
161:
162: /**
163: * Gets the method creator associated with the return type of the method.
164: *
165: * @param logger
166: * @param method method to create
167: * @return the method creator
168: * @throws UnableToCompleteException
169: */
170: protected AbstractMethodCreator getMethodCreator(TreeLogger logger,
171: JMethod method) throws UnableToCompleteException {
172: JType type = method.getReturnType();
173:
174: // TODO make the build work. This is not correct.
175: type = type.getErasedType();
176:
177: AbstractMethodCreator methodCreator = methodFactories.get(type);
178: if (methodCreator == null) {
179: String msg = "No current method creator exists for "
180: + method + " only methods with return types of ";
181: Iterator<JType> iter = this .methodFactories.keySet()
182: .iterator();
183: while (iter.hasNext()) {
184: msg += iter.next().getSimpleSourceName();
185: if (iter.hasNext()) {
186: msg += ", ";
187: }
188: }
189: msg += " can be created";
190: throw error(logger, msg);
191: }
192: return methodCreator;
193: }
194:
195: /**
196: * Gets the associated writer.
197: *
198: * @return writer
199: */
200: protected SourceWriter getWriter() {
201: return writer;
202: }
203:
204: private void emitMethods(TreeLogger logger, JClassType cur)
205: throws UnableToCompleteException {
206: JMethod[] x = getAllInterfaceMethods(cur);
207: for (int i = 0; i < x.length; i++) {
208: genMethod(logger, x[i]);
209: getWriter().println();
210: }
211: }
212:
213: /**
214: * Generates a method declaration for the given method.
215: *
216: * @param method method to generate
217: * @throws UnableToCompleteException
218: */
219: private void genMethod(TreeLogger logger, JMethod method)
220: throws UnableToCompleteException {
221: String name = method.getName();
222: String returnType = method.getReturnType()
223: .getQualifiedSourceName();
224: getWriter().print("public " + returnType + " " + name + "(");
225: JParameter[] params = method.getParameters();
226: for (int i = 0; i < params.length; i++) {
227: if (i != 0) {
228: getWriter().print(",");
229: }
230: getWriter().print(
231: params[i].getType()
232: .getParameterizedQualifiedSourceName()
233: + " arg" + (i));
234: }
235: getWriter().println(") {");
236: getWriter().indent();
237: String methodName = method.getName();
238: TreeLogger branch = branch(logger,
239: "Generating method body for " + methodName + "()");
240: emitMethodBody(branch, method);
241: getWriter().outdent();
242: getWriter().println("}");
243: }
244: }
|