package io.myweb.processor; import com.google.common.base.Function; import com.google.common.collect.FluentIterable; import io.myweb.processor.model.AssetFile; import io.myweb.processor.model.ParsedFilter; import io.myweb.processor.model.ParsedMethod; import io.myweb.processor.model.Provider; import io.myweb.processor.velocity.VelocityLogger; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.context.Context; import org.apache.velocity.runtime.RuntimeConstants; import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader; import javax.annotation.processing.ProcessingEnvironment; import javax.tools.JavaFileObject; import java.io.*; import java.util.List; import java.util.regex.Pattern; import static com.google.common.io.Files.fileTreeTraverser; import static com.google.common.io.Files.isFile; import static org.apache.commons.lang3.StringUtils.substringAfter; import static org.apache.commons.lang3.StringUtils.substringBeforeLast; public class MyCodeGenerator extends ProcessingEnvAware { public static final String PKG_PREFIX = "io.myweb."; private String sourceCodePath = ""; public static class EscTool { public String java(String str) { return str.replaceAll("\\\\","\\\\\\\\"); } } public MyCodeGenerator(ProcessingEnvironment processingEnvironment) { super(processingEnvironment); } public void generateCode(List<ParsedMethod> parsedMethods, List<Provider> providers, List<ParsedFilter> filters) { VelocityEngine ve = instantiateVelocityEngine(); if (!providers.isEmpty()) { generateProviders(ve, providers); } else { generateEndpoints(ve, parsedMethods); generateFilters(ve, filters); generateAssetsInfo(ve, sourceCodePath); generateService(ve, parsedMethods, filters); } } private void generateFilters(VelocityEngine ve, List<ParsedFilter> filters) { for (ParsedFilter filter : filters) { Context ctx = createContext(); ctx.put("filter", filter); generateFromTemplate(ve, ctx, PKG_PREFIX + filter.getGeneratedClassName(), "filter.vm"); } } private void generateProviders(VelocityEngine ve, List<Provider> providers) { for (Provider provider : providers) { Context ctx = createContext(); ctx.put("provider", provider); generateFromTemplate(ve, ctx, PKG_PREFIX + provider.getGeneratedClassName(), "provider.vm"); } } private void generateEndpoints(VelocityEngine ve, List<ParsedMethod> parsedMethods) { for (ParsedMethod pm : parsedMethods) { Context ctx = createContext(); ctx.put("parsedMethod", pm); generateFromTemplate(ve, ctx, PKG_PREFIX + pm.getGeneratedClassName(), "endpoint.vm"); } } private void generateService(VelocityEngine ve, List<ParsedMethod> parsedMethods, List<ParsedFilter> filters) { Context ctx = createContext(); ctx.put("endpoints", parsedMethods); ctx.put("filters", filters); generateFromTemplate(ve, ctx, PKG_PREFIX + "MyServices"); } private VelocityEngine instantiateVelocityEngine() { VelocityEngine ve = new VelocityEngine(); ve.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM, new VelocityLogger(getMessager())); ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); ve.init(); return ve; } private VelocityContext createContext() { VelocityContext velocityContext = new VelocityContext(); velocityContext.put("esc", new EscTool()); return velocityContext; } private void generateAssetsInfo(VelocityEngine ve, String sourceCodePath) { String currentProjectPath = substringBeforeLast(sourceCodePath, "/build/"); final String mywebAssetDir = currentProjectPath + "/src/main/assets/myweb"; FluentIterable<File> filesAndDirs = fileTreeTraverser().breadthFirstTraversal(new File(mywebAssetDir)); FluentIterable<File> files = filesAndDirs.filter(isFile()); FluentIterable<AssetFile> assetFiles = files.transform(new Function<File, AssetFile>() { @Override public AssetFile apply(File f) { String relativePath = substringAfter(f.getAbsolutePath(), mywebAssetDir); return new AssetFile(relativePath, f.length()); } }); generateAssetInfo(ve, assetFiles.toList()); } private void generateAssetInfo(VelocityEngine ve, List<AssetFile> assetFiles) { Context ctx = createContext(); ctx.put("assetFiles", assetFiles); generateFromTemplate(ve, ctx, PKG_PREFIX + "MyAssetInfo"); } private void generateFromTemplate(VelocityEngine ve, Context ctx, String classToGenerate) { generateFromTemplate(ve, ctx, classToGenerate, classToGenerate + ".vm"); } private void generateFromTemplate(VelocityEngine ve, Context ctx, String classToGenerate, String templateName) { Template t = ve.getTemplate(templateName); Writer w = null; try { OutputStream os = null; JavaFileObject sourceFile = getProcessingEnv().getFiler().createSourceFile(classToGenerate); updateSourceCodePath(sourceFile, classToGenerate); os = sourceFile.openOutputStream(); w = new PrintWriter(os); } catch (IOException e) { error("Cannot create file: " + e.toString()); return; } t.merge(ctx, w); try { w.close(); } catch (IOException e) { } } private void updateSourceCodePath(JavaFileObject sourceFile, String classToGenerate) { if (sourceCodePath.length()==0) { String fullPath = sourceFile.toUri().getPath(); fullPath = fullPath.substring(0,fullPath.lastIndexOf("/")); String resourcePath = classToGenerate.replace(".","/"); resourcePath = resourcePath.substring(0,resourcePath.lastIndexOf("/")); sourceCodePath = fullPath.replace(resourcePath, ""); } } }