package me.javaroad.plugins.util; import com.google.common.collect.Maps; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import java.io.File; import java.io.IOException; import java.util.Calendar; import java.util.Date; import java.util.Map; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import lombok.extern.log4j.Log4j; import me.javaroad.plugins.model.Entity; import me.javaroad.plugins.model.Template; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; /** * @author heyx */ @Log4j public abstract class TemplateUtils { private static final String PACKAGE_NAME_REGEX = "package\\s*([a-zA-Z0-9_.]+);"; private static final String CLASS_NAME_REGEX = "public\\s*(class|interface|abstract\\s*class)\\s([A-Z]+[a-zA-Z0-9_]*)\\s*"; private static final Pattern CLASSNAME_PATTERN = Pattern.compile(CLASS_NAME_REGEX); private static final Pattern PACKAGE_NAME_PATTERN = Pattern.compile(PACKAGE_NAME_REGEX); public static void generate(Map<String, Template> templates, Entity entity, String basePackage, String outputPath) { Map<String, Object> context = buildContext(entity, basePackage); templates.forEach((name, template) -> { if (Objects.isNull(template) || StringUtils.isBlank(template.getContent())) { return; } String source = VelocityUtils.evaluate(template.getContent(), context); generateSourceFile(source, outputPath); }); } private static boolean userConfirmedOverride(String name) { return Messages.showYesNoDialog(name + " already exists,\nConfirm Overwrite?", "File Exists", null) == Messages.OK; } private static void generateSourceFile(String source, String baseDir) { String packageName = extractPackage(source); String className = extractClassName(source); String sourcePath = buildSourcePath(baseDir, className, packageName); VirtualFileManager manager = VirtualFileManager.getInstance(); VirtualFile virtualFile = manager.refreshAndFindFileByUrl(VfsUtil.pathToUrl(sourcePath)); if (virtualFile == null || !virtualFile.exists() || userConfirmedOverride(className)) { ApplicationManager.getApplication().runWriteAction(() -> { try { if (virtualFile != null && virtualFile.exists()) { virtualFile.setBinaryContent(source.getBytes("utf8")); } else { File file = new File(sourcePath); FileUtils.writeStringToFile(file, source, "utf8"); manager.refreshAndFindFileByUrl(VfsUtil.pathToUrl(sourcePath)); } } catch (IOException e) { log.error(e); } }); } } private static String extractPackage(String source) { Matcher packageNameMatcher = PACKAGE_NAME_PATTERN.matcher(source); if (packageNameMatcher.find()) { return packageNameMatcher.group(1); } throw new RuntimeException("Template error, missing package"); } private static String extractClassName(String source) { Matcher classNameMatcher = CLASSNAME_PATTERN.matcher(source); if (classNameMatcher.find()) { return classNameMatcher.group(2); } throw new RuntimeException("Template error, missing class"); } private static String buildSourcePath(String baseDir, String className, String packageName) { return baseDir + "/" + packageName.replaceAll("\\.", "/") + "/" + className + ".java"; } private static Map<String, Object> buildContext(Entity entity, String basePackage) { Map<String, Object> context = Maps.newHashMap(); context.put("clazz", entity); context.put("fn", MyStringUtils.class); context.put("BASE_PACKAGE", basePackage); context.put("USER", System.getProperty("user.name")); Calendar calendar = Calendar.getInstance(); context.put("YEAR", calendar.get(Calendar.YEAR)); context.put("MONTH", calendar.get(Calendar.MONTH) + 1); context.put("DAY", calendar.get(Calendar.DAY_OF_MONTH)); Date now = new Date(); context.put("DATE", DateFormatUtils.format(now, "yyyy-MM-dd")); context.put("TIME", DateFormatUtils.format(now, "HH:mm:ss")); context.put("DATE_TIME", DateFormatUtils.format(now, "yyyy-MM-dd HH:mm:ss")); return context; } }