/*
* Copyright 2002-2008 the original author or authors.
*
* 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 org.gwtoolbox.bean.rebind;
import com.google.gwt.core.ext.Generator;
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.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;
import org.gwtoolbox.bean.client.BeanInfo;
import org.gwtoolbox.bean.client.BeanInfoRegistry;
import org.gwtoolbox.bean.rebind.scan.TypeScanner;
import org.gwtoolbox.bean.rebind.selector.BeanClassSelector;
import org.gwtoolbox.bean.rebind.validation.config.BeanValidationConfigHolder;
import org.gwtoolbox.bean.rebind.validation.config.ValidationConfigLoader;
import org.gwtoolbox.commons.generator.rebind.EasyTreeLogger;
import org.gwtoolbox.commons.generator.rebind.LoggingUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Generate the BeanInfoRegistry. This generator scans the the packages (configured using the @BeanScan annotation)
* and picks up all beans. The bean need to be annotated with the annotation as specified in the @BeanScan annotation
* (by default the @Bean is picked up).
*
* @author Uri Boness
*/
public class BeanInfoRegistryGenerator extends Generator {
public String generate(TreeLogger logger, GeneratorContext context, String typeName) throws UnableToCompleteException {
try {
LoggingUtils.setLogger(new EasyTreeLogger(logger));
return doGenerate(logger, context, typeName);
} catch (Exception e) {
logger.log(TreeLogger.ERROR, null, e);
throw new UnableToCompleteException();
} finally {
LoggingUtils.clearLogger();
}
}
public String doGenerate(TreeLogger logger, GeneratorContext context, String typeName) throws Exception {
EasyTreeLogger easyLogger = new EasyTreeLogger(logger);
JClassType type = context.getTypeOracle().findType(typeName);
String packageName = type.getPackage().getName();
String simpleName = type.getSimpleSourceName();
String generatedClassName = "gtx__" + simpleName + "Impl";
String qualifiedBeanClassName = packageName + "." + generatedClassName;
SourceWriter sourceWriter = getSourceWriter(logger, context, type, packageName, generatedClassName);
if (sourceWriter == null) {
return qualifiedBeanClassName;
}
// scanning all types and loading configurations
TypeOracle typeOracle = context.getTypeOracle();
TypeScanner scanner = new TypeScanner(easyLogger, context);
BeanConfigLoader beanConfigLoader = new BeanConfigLoader(typeOracle);
ValidationConfigLoader validationConfigLoader = new ValidationConfigLoader(typeOracle);
try {
scanner.scan(beanConfigLoader, validationConfigLoader);
List<JClassType> beanTypes = new ArrayList<JClassType>();
for (BeanRegistryConfig config : beanConfigLoader.getBeanRegistryConfigs()) {
beanTypes.addAll(scanBeans(easyLogger, context, config.getBeanClassSelector(), config.getPatterns()));
}
write(easyLogger, sourceWriter, context, generatedClassName, beanTypes);
sourceWriter.commit(logger);
} finally {
BeanValidationConfigHolder.clear();
}
return qualifiedBeanClassName;
}
protected SourceWriter getSourceWriter(
TreeLogger logger,
GeneratorContext context,
JClassType superClass,
String packageName,
String simpleClassName) {
PrintWriter printWriter = context.tryCreate(logger, packageName, simpleClassName);
if (printWriter == null) {
return null;
}
ClassSourceFileComposerFactory composerFactory = new ClassSourceFileComposerFactory(packageName, simpleClassName);
composerFactory.setSuperclass(superClass.getQualifiedSourceName());
//TODO add imports here
composerFactory.addImport(BeanInfoRegistry.class.getName());
composerFactory.addImport(BeanInfo.class.getName());
composerFactory.addImport(Map.class.getName());
composerFactory.addImport(HashMap.class.getName());
return composerFactory.createSourceWriter(context, printWriter);
}
protected void write(
EasyTreeLogger logger,
SourceWriter writer,
GeneratorContext context,
String classSimpleName,
List<JClassType> beanTypes) throws UnableToCompleteException {
writer.println();
writeFields(logger, writer, context, classSimpleName, beanTypes);
writeInterfaceMethods(logger, writer, context);
}
protected void writeFields(EasyTreeLogger logger, SourceWriter writer, GeneratorContext context, String classSimpleName, List<JClassType> beanTypes)
throws UnableToCompleteException {
writer.println("private final Map<Class, BeanInfo> beanInfoByType = new HashMap<Class, BeanInfo>();");
writer.println();
writer.println("public " + classSimpleName + "() {");
for (JClassType beanType : beanTypes) {
String beanInfoClassName = BeanInfoGenerator.generate(logger, context, beanType);
writer.println(" beanInfoByType.put(" + beanType.getQualifiedSourceName() + ".class, new " + beanInfoClassName + "(this));");
}
writer.println("}");
}
protected void writeInterfaceMethods(EasyTreeLogger logger, SourceWriter writer, GeneratorContext context) {
writer.beginJavaDocComment();
writer.println("BeanInfoRegistry Interface Methods");
writer.endJavaDocComment();
writer.println();
writer.println("public boolean hasBeanInfo(Class type) {");
writer.println(" return beanInfoByType.containsKey(type);");
writer.println("}");
writer.println();
writer.println("public BeanInfo getBeanInfo(Class type) {");
writer.println(" return (BeanInfo) beanInfoByType.get(type);");
writer.println("}");
writer.println();
}
private List<JClassType> scanBeans(
EasyTreeLogger logger,
GeneratorContext context,
BeanClassSelector beanSelector,
Pattern[] patterns) {
List<JClassType> beanTypes = new ArrayList<JClassType>();
for (Pattern pattern : patterns) {
JPackage[] allPackages = context.getTypeOracle().getPackages();
for (JPackage currentPackage : allPackages) {
logger.debug("Scanning package '" + currentPackage.getName() + "'...");
if (!pattern.matcher(currentPackage.getName()).matches()) {
continue;
}
EasyTreeLogger packageLogger = logger.branchInfo("Scanning package '" + currentPackage.getName() + "'");
scanPackage(packageLogger, context, beanSelector, currentPackage, beanTypes);
}
}
return beanTypes;
}
private void scanPackage(
EasyTreeLogger logger,
GeneratorContext context,
BeanClassSelector beanSelector,
JPackage pkg,
List<JClassType> list) {
JClassType[] types = pkg.getTypes();
for (JClassType type : types) {
if (logger.isLoggable(TreeLogger.Type.DEBUG)) {
logger.debug("Processing type '" + type.getQualifiedSourceName() + "'");
}
if (beanSelector.isBean(type)) {
logger.info("Found bean '" + type.getQualifiedSourceName() + "'");
list.add(type);
}
}
}
}