com.gitee.l0km.codegen.base.generator.Generator Maven / Gradle / Ivy
package com.gitee.l0km.codegen.base.generator;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.exception.MethodInvocationException;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.tools.generic.EscapeTool;
import org.apache.velocity.tools.generic.SortTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitee.l0km.codegen.annotations.CodegenDefaultvalue;
import com.gitee.l0km.codegen.annotations.CodegenInvalidValue;
import com.gitee.l0km.codegen.annotations.CodegenLength;
import com.gitee.l0km.codegen.annotations.CodegenRequired;
import com.gitee.l0km.codegen.base.AbstractSchema;
import com.gitee.l0km.codegen.base.CreateInterfaceSourceConstants;
import com.gitee.l0km.codegen.base.DuplicatedConstants;
import com.gitee.l0km.javadocreader.JavadocReader;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import net.gdface.cli.Context;
import net.gdface.utils.ClassResourceUtils;
/**
* @author guyadong
*
*/
public abstract class Generator implements GeneratorConstants, DuplicatedConstants, CreateInterfaceSourceConstants {
protected static final Logger logger = LoggerFactory.getLogger(Generator.class);
private static final String VM_REG= ".+\\.vm$";
private VelocityContext velocityContext = null;
private VelocityEngine velocityEngine = null;
private CodeWriter codeWriter = null;
private GeneratorConfiguration config = null;
public Generator() {
}
public Generator generate() {
return generate(config.getTemplateFolder());
}
public Generator multiGenerate() {
for(Entry> entry : generateTask().entrySet()){
String taskFolder = entry.getKey();
String path = new File(config.getTemplateFolder(),taskFolder).getPath();
List extends AbstractSchema> sourceInfoList = entry.getValue();
if(sourceInfoList.isEmpty()){
generate(path);
}else{
for(AbstractSchema sourceInfo : sourceInfoList){
velocityContext.put(SOURCE_INFO, sourceInfo);
generate(path);
}
}
}
return this;
}
private Generator generate(String taskPath) {
try {
beforeGenerate(velocityContext, taskPath);
try{
File path = new File(config.getTemplateRoot(), taskPath);
if(config.useClasspathResourceLoader()){
if(taskPath.endsWith(VM_SUFFIX)){
generateFile(ClassResourceUtils.normalizePath(path.getPath(),false));
}else {
File folder = new File(taskPath);
for (String name : getTemplateNames(taskPath)){
generateFile(ClassResourceUtils.normalizePath(new File(folder, name).getPath(),false));
}
}
}else if (path.isFile()) {
generateFile(path.getPath());
}
}finally{
afterGenerate(velocityContext, taskPath);
}
} catch (ResourceNotFoundException e) {
logger.error(e.toString());
} catch (ParseErrorException e) {
logger.error(e.toString());
} catch (MethodInvocationException e) {
logger.error(e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
return this;
}
/**
* 判断{@code templateName}是否为被排除的模板文件
* @param templateName
* @return true if excluded,otherwise false
*/
private boolean isExcludedTmpl(final String templateName){
return null == templateName ? false : Iterables.tryFind(config.getExcludeVms(), new Predicate() {
@Override
public boolean apply(String input) {
return templateName.endsWith(input);
}
}).isPresent();
}
/**
* 判断{@code templateName}是否为被排除的模板文件
* @param templateName
* @return true if excluded,otherwise false
*/
private boolean isIncludedTmpl(final String templateName){
return null == templateName ? false : Iterables.tryFind(config.getIncludeVms(), new Predicate() {
@Override
public boolean apply(String input) {
return templateName.endsWith(input);
}
}).isPresent();
}
/**
* 判断{@code templateName}是否要求生成
* @param templateName
* @return true if excluded,otherwise false
*/
private boolean isNeedGenerate(final String templateName){
if(null == templateName){
return false;
}
if(!config.getIncludeVms().isEmpty()){
return isIncludedTmpl(templateName);
}
if(!config.getExcludeVms().isEmpty()){
return !isExcludedTmpl(templateName);
}
return true;
}
/**
* 执行{@code templateName}对指定的模板生成代码
* @param templateName
* @throws ResourceNotFoundException
* @throws ParseErrorException
* @throws MethodInvocationException
* @throws Exception
*/
private void generateFile(String templateName) throws ResourceNotFoundException, ParseErrorException,
MethodInvocationException, Exception {
if(!isNeedGenerate(templateName)){
return;
}
StringWriter writer = new StringWriter();
// 复位标记
codeWriter.setSaveCurrentFile(true);
beforeGenerateFile(velocityContext, templateName);
try{
logger.info("GENERATING:{}", templateName);
velocityContext.put("template", templateName.replace('\\', '/'));
velocityEngine.mergeTemplate(templateName, "UTF-8", velocityContext, writer);
logger.debug(writer.toString());
if (null == codeWriter){
throw new IllegalArgumentException("the member codeWriter not initialized");
}
codeWriter.write(writer.toString());
}finally{
afterGenerateFile(velocityContext, templateName);
}
}
protected String getCmdLineSyntax() {
return String.format("run%s [options]", this.getClass().getSimpleName());
}
protected abstract GeneratorConfiguration getGeneratorConfiguration();
protected abstract Options getOptions();
private final List getTemplateNames(String subFolder) throws FileNotFoundException {
File templateFolder = new File(new File(config.getTemplateRoot()), subFolder);
if(config.useClasspathResourceLoader()){
return getResourceTemplates(templateFolder.getPath());
}else{
return getFileTemplates(templateFolder.getPath());
}
}
private static final List getFileTemplates(String folder) {
File templateFolder = new File(folder);
if (!templateFolder.exists()){
logger.info("SKIP:not found template folder:{},",templateFolder.getAbsolutePath());
return Collections.emptyList();
}
File[] files = templateFolder.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isFile() && pathname.getName().matches(VM_REG);
}
});
return Lists.transform(Arrays.asList(files), new Function(){
@Override
public String apply(File input) {
return input.getName();
}});
}
private static final List getResourceTemplates(String folder){
if (!ClassResourceUtils.resourceExist(Generator.class, folder)){
logger.info("SKIP:not found resource template folder:{},",folder);
return Collections.emptyList();
}
return ClassResourceUtils.getFilesUnchecked(Generator.class, folder, new ClassResourceUtils.FileFilter() {
@Override
public boolean accept(String filename) {
return filename.matches(VM_REG);
}
});
}
public Generator initEngine() {
Context context = createEngineContext();
// 添加公共内置对象
context.setProperty(GENERATOR_TOOL, GeneratorUtils.class);
context.setProperty(JAVADOC_READER,JavadocReader.class);
context.setProperty(JAVA_CLASS, Class.class);
context.setProperty(INLINE_SOURCE, false);
context.setProperty(CODEGEN_REQUIRED_CLASS,CodegenRequired.class);
context.setProperty(CODEGEN_INVALIDVALUE_CLASS,CodegenInvalidValue.class);
context.setProperty(CODEGEN_DEFAULTVALUE_CLASS,CodegenDefaultvalue.class);
context.setProperty(CODEGEN_LENGTH_CLASS,CodegenLength.class);
velocityEngine = new VelocityEngine();
if(config.useClasspathResourceLoader()){
// 从classpath加载模板
velocityEngine.setProperty(VelocityEngine.RESOURCE_LOADER, "class");
velocityEngine.setProperty("class.resource.loader.description", "Velocity Multi Class path Resource Loader");
//velocityEngine.setProperty("class.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
// 使用自定义的 ResourceLoader
velocityEngine.setProperty("class.resource.loader.class", MultiClasspathResourceLoader.class.getName());
velocityEngine.setProperty("class.resource.loader.path", config.getTemplateRoot());
}else{
// 从文件系统加载模板
velocityEngine.setProperty(VelocityEngine.FILE_RESOURCE_LOADER_PATH, config.getTemplateRoot());
}
/** 允许 set null */
velocityEngine.setProperty(VelocityEngine.SET_NULL_ALLOWED, "true");
velocityEngine.setProperty(VelocityEngine.INPUT_ENCODING, "UTF-8");
velocityEngine.setProperty(VelocityEngine.OUTPUT_ENCODING, "UTF-8");
velocityContext = new VelocityContext(context.getContext());
// 字符串转义工具
velocityContext.put(VELOCITY_ESC, new EscapeTool());
// 排序工具
velocityContext.put(VELOCITY_SORTER, new SortTool());
return this;
}
public Generator parseCommandLine(String[] args) {
HelpFormatter formatter = new HelpFormatter();
CommandLineParser parser = new DefaultParser();
CommandLine cl = null;
Options options = getOptions();
if(!options.hasOption(HELP_OPTION)){
options.addOption(HELP_OPTION, HELP_OPTION_LONG, false, HELP_OPTION_DESC);
}
String formatstr = getCmdLineSyntax();
boolean exit = false;
try {
// 处理Options和参数
cl = parser.parse(getOptions(), args);
if (!cl.hasOption(HELP_OPTION)) {
if (cl.hasOption(DEFINE_OPTION)) {
setSystemProperty(cl.getOptionValues(DEFINE_OPTION));
}
config = getGeneratorConfiguration();
config.loadConfig(options, cl);
} else {
exit = true;
}
} catch (ParseException e) {
logger.error(e.toString());
exit = true;
}
if (exit) {
options.addOption(HELP_OPTION, HELP_OPTION_LONG, false, HELP_OPTION_DESC);
formatter.printHelp(formatstr, options); // 如果发生异常,则打印出帮助信息
System.exit(1);
}
return this;
}
private void setSystemProperty(String[] properties) {
for (int i = 0; i < properties.length; i += 2) {
System.setProperty(properties[i], properties[i + 1]);
logger.info("set property [{}]=[{}]", properties[i], properties[i + 1]);
}
}
/**
* 返回代码写入类对象({@link CodeWriter}),子类可以重写此方法
*/
protected CodeWriter getCodeWriter(){
return new JavaCodeWriter(config.getOutputLocation());
}
protected Context createEngineContext() {
codeWriter = getCodeWriter();
return Context
.builder()
.addProperty(CMD_CONFIG, config)
.addProperty(CODE_WRITER, codeWriter)
.addProperty(INCLUDE_FOLDER, config.getIncludeFolder())
.addProperty(TEMPLATE_FOLDER, config.getTemplateFolder())
.addProperty(
GENERAED_BY,
String.format("计算机生成代码(generated by automated tools %s @author guyadong)", this.getClass()
.getSimpleName())).build();
}
/**
* 在对{@code taskFolder}进行执行生成任务前调用
* 子类可以重写此方法对{@code context}进行修改
* @param context
* @param taskFolder
*/
protected void beforeGenerate(VelocityContext context, String taskFolder){
}
/**
* 在对{@code taskFolder}进行执行生成任务后调用
* 子类可以重写此方法对{@code context}进行修改
* @param context
* @param taskFolder
*/
protected void afterGenerate(VelocityContext context, String taskFolder){
}
protected void beforeGenerateFile(VelocityContext context, String templateName){
}
protected void afterGenerateFile(VelocityContext context, String templateName){
}
/**
* 子类重写此方法返回{@link #multiGenerate()}方法需要的任务数据
* key 模板子文件夹
* value schema对象列表
*/
protected Map> generateTask(){
return Collections.emptyMap();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy