/*
* Copyright 2013 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.web.bindery.event.gwt.rebind.binder;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.Type;
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.TypeOracle;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.web.bindery.event.shared.binder.EventHandler;
import com.google.web.bindery.event.shared.binder.GenericEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Writes implementations of
* {@link com.google.web.bindery.event.shared.binder.impl.AbstractEventBinder}. The
* generated class implements the single abstract doBindEventHandlers method by
* calling bind() for each method in the target annotated with
* {@link EventHandler}.
*
* @author ekuefler@google.com (Erik Kuefler)
*/
class EventBinderWriter {
private final TreeLogger logger;
private final JClassType genericEventType;
EventBinderWriter(TreeLogger logger, JClassType genericEventType) {
this.logger = logger;
this.genericEventType = genericEventType;
}
void writeDoBindEventHandlers(JClassType target, SourceWriter writer, TypeOracle typeOracle)
throws UnableToCompleteException {
writeBindMethodHeader(writer, target.getQualifiedSourceName());
for (JMethod method : target.getInheritableMethods()) {
EventHandler annotation = method.getAnnotation(EventHandler.class);
if (annotation != null) {
writeHandlerForBindMethod(annotation, writer, method, typeOracle);
}
}
writeBindMethodFooter(writer);
}
private void writeBindMethodHeader(SourceWriter writer, String targetName) {
writer.println("protected List<HandlerRegistration> doBindEventHandlers("
+ "final %s target, EventBus eventBus) {",
targetName);
writer.indent();
writer.println(
"List<HandlerRegistration> registrations = new LinkedList<HandlerRegistration>();");
}
private void writeHandlerForBindMethod(EventHandler annotation, SourceWriter writer,
JMethod method, TypeOracle typeOracle) throws UnableToCompleteException {
JClassType eventParameter = null;
if (method.getParameterTypes().length == 1) {
eventParameter = method.getParameterTypes()[0].isClassOrInterface();
}
if (annotation.handles().length == 0 && !isAConcreteGenericEvent(eventParameter)) {
logger.log(Type.ERROR, "Method " + method.getName()
+ " annotated with @EventHandler without event classes must have exactly "
+ "one argument of a concrete type assignable to GenericEvent");
throw new UnableToCompleteException();
}
List<String> eventTypes = new ArrayList<String>();
if (annotation.handles().length != 0) {
for (Class<? extends GenericEvent> event : annotation.handles()) {
String eventTypeName = event.getCanonicalName();
JClassType eventClassType = typeOracle.findType(eventTypeName);
if (eventClassType == null) {
logger.log(Type.ERROR, "Can't resolve " + eventTypeName);
throw new UnableToCompleteException();
}
if (eventParameter != null && !eventClassType.isAssignableTo(eventParameter)) {
logger.log(Type.ERROR, "Event " + eventTypeName + " isn't assignable to "
+ eventParameter.getName() + " in method: " + method.getName());
throw new UnableToCompleteException();
}
eventTypes.add(eventClassType.getQualifiedSourceName());
}
} else {
eventTypes.add(eventParameter.getQualifiedSourceName());
}
for (String eventType : eventTypes) {
writer.println("bind(eventBus, registrations, %s.class, new GenericEventHandler() {",
eventType);
if (eventParameter != null) {
writer.indentln("public void handleEvent(GenericEvent event) { target.%s((%s) event); }",
method.getName(), eventType);
} else {
writer.indentln("public void handleEvent(GenericEvent event) { target.%s(); }",
method.getName());
}
writer.println("});");
}
}
private boolean isAConcreteGenericEvent(JClassType param) {
return param != null && !param.isAbstract() && param.isAssignableTo(genericEventType);
}
private void writeBindMethodFooter(SourceWriter writer) {
writer.println("return registrations;");
writer.outdent();
writer.println("}");
}
}