/** * Copyright 2010 Bing Ran<bing_ran@hotmail.com> * * 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 cn.bran.japid.compiler; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.lang.annotation.Annotation; import java.util.regex.Pattern; import cn.bran.japid.classmeta.AbstractTemplateClassMetaData; import cn.bran.japid.classmeta.MimeTypeEnum; import cn.bran.japid.template.JapidTemplate; import cn.bran.japid.util.DirUtil; /** * compile html based template to java files * * The facade to all the compiler suite and configurations. * * @author Bing Ran<bing_ran@hotmail.com> * */ public class JapidTemplateTransformer { private static final String HTML = ".html"; private String sourceFolder; private String targetFolder; private boolean usePlay = true; // private MessageProvider messageProvider; // private UrlMapper urlMapper; /** * @param sourceFolder * the folder containing the template source tree. It's the same * concept as in eclipse. The root package for Java artifacts are * the direct children of this * @param targetFolder * the "source folder", in Eclipse term, that the generated Java * artifacts will be placed. If it is null, the Java files will * be placed in the sourceFolder. */ public JapidTemplateTransformer(String sourceFolder, String targetFolder) { super(); this.sourceFolder = sourceFolder; // this.messageProvider = messageProvider; // this.urlMapper = urlMapper; this.targetFolder = targetFolder; // // BranTemplateBase.messageProvider = messageProvider; // BranTemplateBase.urlMapper = urlMapper; } /** * * @param importLine * add an import to all the files generated. For examples: * "my.package.*", "my.package.MyClass" */ public static void addImportLine(String importLine) { AbstractTemplateClassMetaData.addImportLineGlobal(importLine); } /** * effectively as in Java: "import static my.Tools.*;" if Tools.class is the * parameter. * * @param class1 */ public static void addImportStatic(Class<?> class1) { AbstractTemplateClassMetaData.addImportStatic(class1); } static Pattern doLayoutTag = Pattern.compile(".*\\#\\{\\s*doLayout\\s*.*"); static Pattern doLayoutDirective = Pattern.compile(".*[`@]doLayout"); static Pattern doLayoutDirective2 = Pattern.compile(".*[`@]doLayout\\s?[`@].*"); static Pattern getTag= Pattern.compile(".*\\#\\{\\s*get\\s*.*"); static Pattern getDirective = Pattern.compile(".*[`@]get\\s+\\w+\\s*"); public static boolean looksLikeLayout(String src) { String[] split = src.split("[\r\n]"); for (String line : split) { line = line.trim(); if (doLayoutTag.matcher(line).matches() || doLayoutDirective.matcher(line).matches() || doLayoutDirective2.matcher(line).matches() || getTag.matcher(line).matches() || getDirective.matcher(line).matches()) { return true; } } return false; } /** * * @param fileName * the relative path of the template file from the source folder, * e.g., "my/path/mytemplate.html", which maps to * my.path.mytemplate.java * @return * @throws Exception */ public File generate(String fileName) throws Exception { String realSrcFile = sourceFolder == null ? fileName : sourceFolder + "/" + fileName; String src = DirUtil.readFileAsString(realSrcFile); JapidTemplate temp = new JapidTemplate(fileName, src); JapidAbstractCompiler c = selectCompiler(src); c.setUseWithPlay(usePlay); c.compile(temp); String jsrc = temp.javaSource; String fileNameRoot = DirUtil.mapSrcToJava(fileName); String target = targetFolder == null ? sourceFolder : targetFolder; String realTargetFile = target == null ? fileNameRoot : target + "/" + fileNameRoot; File f = DirUtil.writeToFile(jsrc, realTargetFile); return f; } public static JapidAbstractCompiler selectCompiler(String src) { JapidAbstractCompiler c = null; // TODO: more robust way of determine layout file or view file if (looksLikeLayout(src)) { c = new JapidLayoutCompiler(); } else { // regular template and tag are the same thing c = new JapidTemplateCompiler(); } return c; } /** * compile a script with the designated class name and MIME type * * @author Bing Ran (bing.ran@hotmail.com) * @param scriptSrc * @param fqName * @param mime * @return */ public static String generateInMemory(String scriptSrc, String fqName, MimeTypeEnum mime, boolean usePlay) { JapidTemplate temp = new JapidTemplate(fqName, mime, scriptSrc); return compileJapid(scriptSrc, usePlay, temp); } /** * * @author Bing Ran (bing.ran@hotmail.com) * @param scriptSrc the Japid script source code * @param srcFileName the full path to the script file. Used to parse package and class name * @return the generated Java code * */ public static String generateInMemory(String scriptSrc, String srcFileName, boolean usePlay) { JapidTemplate temp = new JapidTemplate(srcFileName, scriptSrc); return compileJapid(scriptSrc, usePlay, temp); } private static String compileJapid(String scriptSrc, boolean usePlay, JapidTemplate temp) { JapidAbstractCompiler c = null; if (looksLikeLayout(scriptSrc)) { c = new JapidLayoutCompiler(); } else { // regular template and tag are the same thing c = new JapidTemplateCompiler(); } c.setUseWithPlay(usePlay); c.compile(temp); String jsrc = temp.javaSource; return jsrc; } /** * a utility method. Should be somewhere else. * * @param srcDir * @param cf * @throws IOException */ public static String getRelativePath(File child, File parent) throws IOException { String curPath = parent.getCanonicalPath(); String childPath = child.getCanonicalPath(); assert (childPath.startsWith(curPath)); String srcRelative = childPath.substring(curPath.length()); if (srcRelative.startsWith(File.separator)) { srcRelative = srcRelative.substring(File.separator.length()); } return srcRelative; } /** * transform a source template to Java * * @param file * the source file that must be a descendant of the source folder. * @return * @throws Exception */ public File generate(File file) throws Exception { String rela = DirUtil.getRelativePath(file, new File(".")); return generate(rela); } /** * add class level annotation for whatever purpose * * @param anno */ public static void addAnnotation(Class<? extends Annotation> anno) { AbstractTemplateClassMetaData.addAnnotation(anno); // typeAnnotations.add(anno); } public void usePlay(boolean b) { this.usePlay = b; } // List<Class<? extends Annotation>> typeAnnotations = new ArrayList<Class<? // extends Annotation>>(); }