package org.gwtoolbox.ioc.core.rebind.processor.scanning;
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.JPackage;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.client.rpc.RemoteService;
import org.gwtoolbox.commons.generator.rebind.EasyTreeLogger;
import org.gwtoolbox.commons.generator.rebind.PatternUtils;
import org.gwtoolbox.commons.generator.rebind.StringUtils;
import org.gwtoolbox.ioc.core.client.annotation.Component;
import org.gwtoolbox.ioc.core.client.annotation.ComponentName;
import org.gwtoolbox.ioc.core.client.annotation.ComponentScan;
import org.gwtoolbox.ioc.core.client.annotation.Scope;
import org.gwtoolbox.ioc.core.rebind.ProcessorInitializationException;
import org.gwtoolbox.ioc.core.rebind.config.MutableComponentContainerOracle;
import org.gwtoolbox.ioc.core.rebind.config.SimpleComponentDefinition;
import org.gwtoolbox.ioc.core.rebind.processor.AbstractComponentContainerProcessor;
import org.gwtoolbox.ioc.core.rebind.processor.StandardSimpleComponentDefinitionProcessor;
import java.util.regex.Pattern;
/**
* @author Uri Boness
*/
public class ComponentScanProcessor extends AbstractComponentContainerProcessor<ComponentScan> {
private Pattern[] patterns;
private boolean scanRemoteServices;
private final static StandardSimpleComponentDefinitionProcessor componentProcessor = new StandardSimpleComponentDefinitionProcessor();
public void doInit(EasyTreeLogger logger, ComponentScan componentScan, JClassType containerType, GeneratorContext context) throws ProcessorInitializationException {
this.scanRemoteServices = componentScan.scaneRemoteServices();
String[] packages = componentScan.packages();
patterns = new Pattern[packages.length];
for (int i=0; i < packages.length ; i++) {
patterns[i] = PatternUtils.resolvePattern(packages[i], componentScan.resolver());
}
}
public void doProcess(EasyTreeLogger logger, MutableComponentContainerOracle oracle, GeneratorContext context) throws Exception {
for (Pattern pattern : patterns) {
JPackage[] allPackages = context.getTypeOracle().getPackages();
for (JPackage currentPackage : allPackages) {
logger.debug("Processing package '" + currentPackage.getName() + "'...");
if (!pattern.matcher(currentPackage.getName()).matches()) {
continue;
}
EasyTreeLogger packageLogger = logger.branchInfo("Scanning package '" + currentPackage.getName() + "'");
processPackage(packageLogger, oracle, context, currentPackage);
}
}
}
protected void processPackage(EasyTreeLogger logger, MutableComponentContainerOracle oracle, GeneratorContext context, JPackage pkg)
throws UnableToCompleteException {
JClassType[] types = pkg.getTypes();
for (JClassType type : types) {
if (logger.isLoggable(TreeLogger.Type.DEBUG)) {
logger.debug("Processing type '" + type.getQualifiedSourceName() + "'");
}
if (isComponent(type)) {
if (logger.isLoggable(TreeLogger.Type.TRACE)) {
logger.trace("Found component type '" + type.getQualifiedSourceName() + "'");
}
SimpleComponentDefinition componentDefinition = loadComponentDefinition(logger, type, context.getTypeOracle());
oracle.registerComponentDefinition(componentDefinition);
continue;
}
if (scanRemoteServices && isRemoteService(type, context)) {
if (logger.isLoggable(TreeLogger.Type.TRACE)) {
logger.trace("Found remote service type '" + type.getQualifiedSourceName() + "'");
}
SimpleComponentDefinition componentDefinition = loadRemoteServiceComponentDefinition(logger, type, context.getTypeOracle());
oracle.registerComponentDefinition(componentDefinition);
}
}
}
//TODO: add support for stereotyping (a la spring)
protected boolean isComponent(JClassType type) {
return type.isAnnotationPresent(Component.class);
}
protected boolean isRemoteService(JClassType type, GeneratorContext context) {
JClassType remoteServiceType = context.getTypeOracle().findType(RemoteService.class.getName());
return type.isAssignableTo(remoteServiceType);
}
protected SimpleComponentDefinition loadComponentDefinition(EasyTreeLogger logger, JClassType type, TypeOracle typeOracle)
throws UnableToCompleteException {
Component component = type.getAnnotation(Component.class);
String name = component.name();
if ("".equals(name)) {
name = StringUtils.uncapitalize(type.getSimpleSourceName());
}
SimpleComponentDefinition definition = new SimpleComponentDefinition(name, type, component.scope() == Scope.SINGLETON);
definition.setLazy(component.lazyInit());
String initMethodName = component.initMethodName();
if (!"".equals(initMethodName)) {
definition.setInitMethodName(initMethodName);
}
String disposeMethodName = component.disposeMethodName();
if (!"".equals(disposeMethodName)) {
definition.setDisposeMethodName(disposeMethodName);
}
componentProcessor.process(logger, definition, typeOracle);
return definition;
}
protected SimpleComponentDefinition loadRemoteServiceComponentDefinition(EasyTreeLogger logger, JClassType remoteType, TypeOracle typeOracle)
throws UnableToCompleteException {
String name = (remoteType.isAnnotationPresent(ComponentName.class)) ?
remoteType.getAnnotation(ComponentName.class).value() :
StringUtils.uncapitalize(remoteType.getSimpleSourceName());
String asyncTypeName = remoteType.getQualifiedSourceName() + "Async";
JClassType asyncType = typeOracle.findType(asyncTypeName);
SimpleComponentDefinition definition = new SimpleComponentDefinition(name, remoteType);
definition.setGeneratedType(asyncType);
return definition;
}
}