package org.gwtoolbox.ioc.core.rebind.processor.multicaster;
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.Generator;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.core.ext.typeinfo.JPackage;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import com.google.gwt.user.client.Command;
import org.gwtoolbox.commons.generator.rebind.EasyTreeLogger;
import org.gwtoolbox.ioc.core.client.event.ApplicationEvent;
import org.gwtoolbox.ioc.core.client.event.ApplicationEventListener;
import org.gwtoolbox.ioc.core.client.event.DefaultApplicationEventMulticaster;
import org.gwtoolbox.ioc.core.client.annotation.EventPackages;
import java.io.PrintWriter;
import java.util.*;
/**
* @author Uri Boness
*/
public class MulticasterClassGenerator extends Generator {
public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
Set<JClassType> eventTypes = new HashSet<JClassType>();
TypeOracle typeOracle = context.getTypeOracle();
JClassType type = typeOracle.findType(typeName);
if (type.isAnnotationPresent(EventPackages.class)) {
JClassType eventType = typeOracle.findType(ApplicationEvent.class.getName());
EventPackages eventPackages = type.getAnnotation(EventPackages.class);
String[] patterns = eventPackages.value();
for (JPackage pkg : typeOracle.getPackages()) {
for (String pattern : patterns) {
if (pkg.getName().matches(pattern)) {
addEventTypes(pkg, eventTypes, eventType);
}
}
}
}
return generate(new EasyTreeLogger(logger), type, eventTypes, context);
}
public static String generate(EasyTreeLogger logger, JClassType multicasterType, Set<JClassType> eventTypes, GeneratorContext context) throws UnableToCompleteException {
TypeOracle typeOracle = context.getTypeOracle();
String packageName = multicasterType.getPackage().getName();
String newClassName = multicasterType.getSimpleSourceName() + "Impl";
String newQualifiedClassName = packageName + "." + newClassName;
SourceWriter sourceWriter = getSourceWriter(logger, context, packageName, multicasterType, newClassName);
if (sourceWriter == null) {
return newQualifiedClassName;
}
write(logger, sourceWriter, typeOracle, context, multicasterType, eventTypes);
sourceWriter.commit(logger);
return newQualifiedClassName;
}
//================================================ Helper Methods ==================================================
protected static void addEventTypes(JPackage pkg, Set<JClassType> types, JClassType eventType) {
for (JClassType type : pkg.getTypes()) {
if (type.isAssignableTo(eventType)) {
types.add(type);
}
}
}
protected static SourceWriter getSourceWriter(
TreeLogger logger,
GeneratorContext context,
String packageName,
JClassType parentType,
String multicasterClassName) {
PrintWriter printWriter = context.tryCreate(logger, packageName, multicasterClassName);
if (printWriter == null) {
return null;
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, multicasterClassName);
composerFactory.addImport(List.class.getName());
composerFactory.addImport(LinkedList.class.getName());
composerFactory.addImport(Command.class.getName());
composerFactory.addImport(ApplicationEvent.class.getName());
composerFactory.addImport(ApplicationEventListener.class.getName());
composerFactory.setSuperclass(parentType.getQualifiedSourceName());
return composerFactory.createSourceWriter(context, printWriter);
}
protected static void write(
EasyTreeLogger logger,
SourceWriter writer,
TypeOracle typeOracle,
GeneratorContext context,
JClassType multicasterType,
Set<JClassType> eventTypes) throws UnableToCompleteException {
Map<String, String> listNameByEventName = new HashMap<String, String>();
int count = 0;
writer.println();
for (JClassType eventType : eventTypes) {
String listName = "listeners_" + (count++);
writer.println("private final List<ApplicationEventListener> " + listName + " = new LinkedList<ApplicationEventListener>();");
listNameByEventName.put(eventType.getQualifiedSourceName(), listName);
}
JClassType defaultMulticasterType = typeOracle.findType(DefaultApplicationEventMulticaster.class.getName());
if (!multicasterType.isAssignableTo(defaultMulticasterType)) {
writer.println("private final List<ApplicationEventListener> listeners = new LinkedList<ApplicationEventListener>();");
}
writer.println();
boolean first = true;
writer.println("public void notifyEvent(ApplicationEvent event) {");
for (JClassType eventType : eventTypes) {
if (!first) {
writer.println("else");
}
first = false;
String eventName = eventType.getQualifiedSourceName();
String listName = listNameByEventName.get(eventName);
writer.println("if (event instanceof " + eventName + ") {");
writer.println(" for (ApplicationEventListener listener : " + listName + ".toArray(new ApplicationEventListener[" + listName + ".size()])) {");
writer.println(" listener.handle(event);");
writer.println(" }");
writer.println("}");
}
if (!eventTypes.isEmpty()) {
writer.println("else {");
}
writer.println(" for (ApplicationEventListener listener : listeners.toArray(new ApplicationEventListener[listeners.size()])) {");
writer.println(" listener.handle(event);");
writer.println(" }");
if (!eventTypes.isEmpty()) {
writer.println("}");
}
writer.println("for (Command command : event.getPostEventCommands()) {");
writer.println(" command.execute();");
writer.println("}");
writer.println("}");
first = true;
writer.println("public void registerListener(ApplicationEventListener listener) {");
for (JClassType eventType : eventTypes) {
if (!first) {
writer.println("else");
}
first = false;
String eventName = eventType.getQualifiedSourceName();
String listName = listNameByEventName.get(eventName);
writer.println("if (event instanceof " + eventName + ") {");
writer.println(" " + listName + ".add(event);");
writer.println("}");
}
if (!eventTypes.isEmpty()) {
writer.println("else {");
}
writer.println(" listeners.add(event);");
writer.println("}");
first = true;
writer.println("public void unregisterListener(ApplicationEventListener listener) {");
for (JClassType eventType : eventTypes) {
if (!first) {
writer.println("else");
}
first = false;
String eventName = eventType.getQualifiedSourceName();
String listName = listNameByEventName.get(eventName);
writer.println("if (event instanceof " + eventName + ") {");
writer.println(" " + listName + ".remove(event);");
writer.println("}");
}
if (!eventTypes.isEmpty()) {
writer.println("else {");
}
writer.println(" listeners.remove(event);");
writer.println("}");
writer.println("public void clearListeners() {");
for (String listName : listNameByEventName.values()) {
writer.println(" " + listName + ".clear();");
}
writer.println("listeners.clear();");
writer.println("}");
}
}