/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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.civilian.tool.scaffold; import java.io.File; import java.io.IOException; import java.net.URL; import java.nio.file.Files; import java.util.regex.Pattern; import org.civilian.internal.source.OutputLocation; import org.civilian.tool.csp.CspCompiler; import org.civilian.tool.csp.CspException; import org.civilian.util.Arguments; import org.civilian.util.Check; import org.civilian.util.StringUtil; /** * The scaffold command-line tool. * Run without arguments to obtain a detailed help message. */ public class Scaffold { private static final String DEFAULT_ENCODING = "UTF-8"; private static final Pattern LIST_SPLT = Pattern.compile("\\s*,\\s*"); public static void main(String[] s) throws Exception { Arguments args = new Arguments(s); if (!args.hasMore()) { printHelp(); return; } else run(args); } private static void printHelp() { System.out.println("Usage:"); System.out.println("java " + Scaffold.class.getName() + " [<parameter>]* <dir> <app-prefix>"); System.out.println(); System.out.println("Arguments"); System.out.println("dir the project directory"); System.out.println("app-prefix (short) prefix of core application classes"); System.out.println(); System.out.println("Parameters: default:"); System.out.println("-eclipse create eclipse project files"); System.out.println("-enc <encoding> encoding of generated files " + DEFAULT_ENCODING); System.out.println("-libs <list> jar files to copy to WEB-INF/lib"); System.out.println("-locales <list> comma-sep. list of sup. locales en"); System.out.println("-min create a minimal scaffold project"); System.out.println("-package <package> base application package based on app prefix"); System.out.println("-tomcat create tomcat server.xml snippet"); System.out.println("-text creates initial msgbundles"); System.out.println("-v verbose"); } private static void run(Arguments args) throws Exception { Options options = new Options(); while(args.startsWith("-")) { if (args.consume("-eclipse")) options.eclipse = true; else if (args.consume("-enc")) options.encoding = args.next("encoding"); else if (args.consume("-libs")) options.libs = args.next("libs"); else if (args.consume("-locales")) options.locales = args.next("locales"); else if (args.consume("-min")) options.minimal = true; else if (args.consume("-package")) options.basePackage = args.next("package"); else if (args.consume("-text")) options.text = true; else if (args.consume("-tomcat")) options.tomcat = true; else if (args.consume("-v")) options.verbose = true; else throw new IllegalArgumentException("unknown option " + args.next()); } options.dir = args.nextFile("directory").getAbsoluteFile(); options.appPrefix = args.next("app-prefix"); Scaffold scaffold = new Scaffold(options); scaffold.run(); } public Scaffold(Options options) { options_ = Check.notNull(options, "options"); options_.complete(); Log.setVerbose(options.verbose); project_ = new Project(options.dir, options.encoding, options_.basePackage); } public void run() throws Exception { Log.print("creating project in " + project_.root); createVariables(); writeStandardFiles(); if (options_.eclipse) writeEclipseFiles(); if (options_.text) writeTextFiles(); if (options_.tomcat) writeTomcatFiles(); Log.print("done"); } private void createVariables() { String appId = options_.appPrefix.toLowerCase(); vars_ = new VariableMap(); appClass_ = vars_.put(new ClassVar("appClass", options_.appPrefix + "App")); pathParamsClass_ = vars_.put(new ClassVar("pathParamsClass", options_.appPrefix + "PathParams")); resourcesClass_ = vars_.put(new ClassVar("resourcesClass", options_.appPrefix + "Resources")); appCtrlClass_ = vars_.put(new ClassVar("appController", options_.appPrefix + "Controller")); vars_.put(new Variable("encoding", options_.encoding)); vars_.put(new Variable("appPrefix", options_.appPrefix)); vars_.put(new Variable("appId", appId)); vars_.put(new Variable("webPackage", project_.srcWeb.packageName)); vars_.put(new Variable("locales", options_.locales)); vars_.put(new Variable("minComment", options_.minimal ? "// " : "")); vars_.put(new Variable("appMsgsIni", options_.text ? "app." + appId + ".messages = resbundle:" + project_.srcText.packagePath + "/msg\n" : "\n")); } private void writeStandardFiles() throws Exception { Log.print("write standard files"); ResourceDir dir = new ResourceDir(vars_); dir.resource("build.xml").writeTo(project_.root); dir.resource("build.properties").writeTo(project_.root); dir.resource("ivy.xml").writeTo(project_.root); dir.resource("web.xml").writeTo(project_.webInf, "UTF-8"); dir.resource("simplelogger.properties").writeTo(project_.webInfClasses); dir.resource("App.java.res").setFile(appClass_).writeTo(project_.srcWeb); dir.resource("AppPathParams.java.res").setFile(pathParamsClass_.file).writeTo(project_.srcWeb); dir.resource("AppController.java.res").setFile(appCtrlClass_.file).writeTo(project_.srcWeb); project_.bin.makeDir(); if (!options_.minimal) { dir.resource("civilian.ini").writeTo(project_.webInf); dir.resource("style.css").writeTo(project_.web); dir.resource("AppResources.java.res").setFile(resourcesClass_.file).writeTo(project_.srcWeb); dir.resource("IndexController.java.res").writeTo(project_.srcWeb); dir.resource("IndexTemplate.csp.res").writeTo(project_.srcWeb); dir.resource("users$UsersController.java.res").writeTo(project_.srcWebUsers); dir.resource("users$IndexController.java.res").writeTo(project_.srcWebUsers); dir.resource("userId$UserController.java.res").writeTo(project_.srcWebUserId); dir.resource("userId$IndexController.java.res").writeTo(project_.srcWebUserId); dir.resource("userId$package-info.java.res").writeTo(project_.srcWebUserId); } else { dir.resource("civilian.ini.min").writeTo(project_.webInf); dir.resource("AppResources.java.min").setFile(resourcesClass_.file).writeTo(project_.srcWeb); dir.resource("IndexController.java.min").writeTo(project_.srcWeb); } copyLibs(); runCspCompiler(); } private void copyLibs() throws IOException { // copy all jars from the lib-directory if (options_.libs != null) { String[] entries = LIST_SPLT.split(options_.libs); for (String entry : entries) copyLib(new File(entry)); } // copy the jar file if the Scaffold class is inside a jar file URL selfUrl = getClass().getResource(getClass().getSimpleName() + ".class"); if (selfUrl != null) { String selfPath = selfUrl.getPath(); if (selfPath.startsWith("file:")) { File jarFile = new File(selfPath.substring(5, selfPath.lastIndexOf("!"))); if (jarFile.exists()) copyLib(jarFile); } } } private void copyLib(File fileOrDir) throws IOException { if (!fileOrDir.exists()) throw new IOException("lib " + fileOrDir.getAbsolutePath() + " does not exist"); else if (fileOrDir.isFile()) { project_.lib.makeDir(); File target = new File(project_.lib, fileOrDir.getName()); if (!target.exists()) Files.copy(fileOrDir.toPath(), target.toPath()); } else { File[] files = fileOrDir.listFiles(); if (files != null) { for (File file : files) { if (file.isFile() && file.getName().endsWith(".jar")) copyLib(file); } } } } private void runCspCompiler() throws CspException, IOException { CspCompiler compiler = new CspCompiler(); CspCompiler.Options options = compiler.options(); options.force = true; options.verbose = options_.verbose ? 1 : 0; options.setEncoding(options_.encoding); options.outputLocation = OutputLocation.OUTPUT_TO_INPUT_DIR; compiler.compile(project_.src); } private void writeEclipseFiles() throws IOException { Log.print("write ecplise files"); ResourceDir eclipseDir = new ResourceDir(vars_, "eclipse"); Resource cpFile = eclipseDir.resource(".classpath"); StringBuilder libs = new StringBuilder(); String path = project_.webInfLib.getRelativePath() + "/"; File[] libFiles = project_.webInfLib.listFiles(); if (libFiles != null) { for (File file : libFiles) { if (file.getName().endsWith(".jar")) libs.append("\t<classpathentry kind=\"lib\" path=\"" + path + file.getName() + "\"/>\n"); } } cpFile.replace("$libs", libs.toString()); cpFile.replace("$src", project_.src.getRelativePath()); cpFile.replace("$bin", project_.bin.getRelativePath()); cpFile.writeTo(project_.root, "UTF-8"); eclipseDir.resource(".project").writeTo(project_.root, "UTF-8"); eclipseDir.resource("org.eclipse.core.resources.prefs").writeTo(project_.settings); } private void writeTextFiles() throws Exception { Log.print("write text files"); ResourceDir textDir = new ResourceDir(vars_, "text"); Resource resource = textDir.resource("msg.properties"); String[] locales = LIST_SPLT.split(options_.locales); for (int i=0; i<locales.length; i++) resource.setFile("msg_" + locales[i] + ".properties").writeTo(project_.srcText, "ISO-8859-1"); } private void writeTomcatFiles() throws Exception { Log.print("write tomcat files"); ResourceDir tomcatDir = new ResourceDir(vars_, "tomcat"); Resource resource = tomcatDir.resource("tomcat.server.xml"); resource.replace("$docbase", project_.web.getAbsolutePath()); resource.replace("$classpath", project_.bin.getAbsolutePath()); resource.writeTo(project_.root); } private static class Options { public String appPrefix; public String basePackage; public File dir; public boolean eclipse; public String encoding; public String libs; public String locales; public boolean minimal; public boolean text; public boolean tomcat; public boolean verbose; private void complete() { Check.notNull(dir, "directory"); checkPrefix(); if (encoding == null) encoding = DEFAULT_ENCODING; if (basePackage == null) basePackage = "com." + appPrefix.toLowerCase(); if (locales == null) locales = "en"; } private void checkPrefix() { Check.notEmpty(appPrefix, "appPrefix"); appPrefix = StringUtil.startUpperCase(appPrefix); if (!isValidJavaPrefix(appPrefix)) throw new IllegalArgumentException("appPrefix '" + appPrefix + "' is not a valid Java class prefix"); } private boolean isValidJavaPrefix(String appPrefix) { if (!Character.isJavaIdentifierStart(appPrefix.charAt(0))) return false; for (int i=1; i<appPrefix.length(); i++) { if (!Character.isJavaIdentifierPart(appPrefix.charAt(i))) return false; } return true; } } private Options options_; private Project project_; private VariableMap vars_; private ClassVar appClass_; private ClassVar pathParamsClass_; private ClassVar resourcesClass_; private ClassVar appCtrlClass_; }