/*
* This software is distributed under the terms of the FSF
* Gnu Lesser General Public License (see lgpl.txt).
*
* This program is distributed WITHOUT ANY WARRANTY. See the
* GNU General Public License for more details.
*/
package com.scooterframework.tools.generator;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import com.scooterframework.admin.ApplicationConfig;
import com.scooterframework.common.util.WordUtil;
import com.scooterframework.tools.common.AbstractGenerator;
import com.scooterframework.tools.common.AmbiguousAppNameException;
import com.scooterframework.tools.common.Generator;
import com.scooterframework.tools.common.ToolsUtil;
/**
* CodeGenerator generates code for complete CRUD operations.
*
* <p>
* Usage examples:
* <pre>
Usage:
java -jar tools/generate.jar [app_path] scaffold {model_name_in_singular_form}[@connection_name]
java -jar tools/generate.jar [app_path] scaffold-ajax {model_name_in_singular_form}[@connection_name]
java -jar tools/generate.jar [app_path] controller controller_name_in_plural_form [method] [method] ...
java -jar tools/generate.jar [app_path] model {model_name_in_singular_form}[@connection_name]
Options:
-Dnoenhance -- Do not allow byte code enhancement. Default is allowed.
-Dtable=YourTable -- Explicitly specify a table name for the model.
Examples:
This page:
java -jar tools/generate.jar -help
Generate scaffold code for blog app's domain named post:
java -jar tools/generate.jar blog scaffold post
Generate ajax scaffold code for blog app's domain named post:
java -jar tools/generate.jar blog scaffold-ajax post
Generate scaffold code for blog app's domain named post based on blog_oracle database:
java -jar tools/generate.jar blog scaffold post@blog_oracle
Generate scaffold code for blog app's domain named post which maps to table message:
java -Dtable=message -jar tools/generate.jar blog scaffold post
Generate scaffold code for blog app's domain named post without allowing enhancement:
java -Dnoenhance -jar tools/generate.jar blog scaffold post
Generate scaffold code of post model for blog app in user home directory:
java -jar tools/generate.jar /home/john/projects/blog scaffold post
Generate scaffold code for blog app's domain named post when blog is the only app under webapps:
java -jar tools/generate.jar scaffold post
Generate controller code for blog app's domain post with index and show actions:
java -jar tools/generate.jar blog controller posts index show
Generate controller code for domain post with index and show actions when blog is the only app under webapps:
java -jar tools/generate.jar controller posts index show
Generate model code for blog app's domain post:
java -jar tools/generate.jar blog model post
Generate model code for domain post when blog is the only app under webapps:
java -jar tools/generate.jar model post
* </pre>
* </p>
*
* @author (Fei) John Chen
*/
public class CodeGenerator {
/**
* @param args
*/
public static void main(String[] args) {
if (args.length < 1 || args[0].equalsIgnoreCase("-help")) {
usage();
return;
}
try {
doTheWork(args);
}
catch(AmbiguousAppNameException ax) {
log("ERROR ERROR ERROR: " + ax.getMessage());
}
catch(Throwable ex) {
ex.printStackTrace();
log("ERROR ERROR ERROR: " + ex.getMessage());
}
if (AbstractGenerator.frameworkInitiated)
ApplicationConfig.configInstanceForApp().endApplication();
}
private static void doTheWork(String[] args) throws Throwable {
String scooterHome = ToolsUtil.setSystemProperty("scooter.home", ToolsUtil.detectRootPath());
String defaultWebappsName = ToolsUtil.setSystemProperty("webapps.name", "webapps");
boolean useImplicitAppName = false;
String appName = "";
String webappsPath = "";
String webappPath = "";
String firstArg = args[0];
if (isTypeName(firstArg)) {
webappsPath = scooterHome + File.separator + defaultWebappsName;
appName = ToolsUtil.detectImplicitAppName(webappsPath);
webappPath = webappsPath + File.separator + appName;
useImplicitAppName = true;
}
else {
if (ToolsUtil.containsPath(firstArg)) {
String[] ss = ToolsUtil.getPathAndName(firstArg);
webappsPath = ss[0];
webappPath = ss[1];
appName = ss[2];
}
else {
appName = firstArg;
webappsPath = scooterHome + File.separator + defaultWebappsName;
webappPath = webappsPath + File.separator + appName;
}
}
appName = appName.toLowerCase();
System.setProperty("app.name", appName);
webappsPath = ToolsUtil.setSystemProperty("webapps.path", webappsPath);
ToolsUtil.validatePathExistence(webappsPath);
webappPath = ToolsUtil.setSystemProperty("app.path", webappPath);
ToolsUtil.validatePathExistence(webappPath);
String appLogs = ToolsUtil.setSystemProperty("app.logs", (scooterHome + File.separator + "logs"));
ToolsUtil.validatePathExistence(appLogs);
String classFiles = webappPath + File.separator + "WEB-INF" + File.separator + "classes";
System.setProperty(ApplicationConfig.SYSTEM_KEY_CLASSFILE, classFiles);
ToolsUtil.validatePathExistence(classFiles);
String propertyFiles = webappPath + File.separator + "WEB-INF" + File.separator + "config";
System.setProperty(ApplicationConfig.SYSTEM_KEY_PROPERTYFILE, propertyFiles);
ToolsUtil.validatePathExistence(propertyFiles);
String sourceFiles = webappPath + File.separator + "WEB-INF" + File.separator + "src";
System.setProperty(ApplicationConfig.SYSTEM_KEY_SOURCEFILE, sourceFiles);
ToolsUtil.validatePathExistence(sourceFiles);
String referenceFiles = scooterHome + File.separator + "lib";
System.setProperty(ApplicationConfig.SYSTEM_KEY_REFERENCEFILE, referenceFiles);
ToolsUtil.validatePathExistence(referenceFiles);
String pluginFiles = scooterHome + File.separator + "plugins";
System.setProperty(ApplicationConfig.SYSTEM_KEY_PLUGINFILE, pluginFiles);
ToolsUtil.validatePathExistence(pluginFiles);
String targetDir = webappPath;
log("Generating code for app named " + appName + ":");
log("scooter.home: " + scooterHome);
log("Target dir: " + targetDir);
//create all properties
Map<String, String> allProps = new HashMap<String, String>();
allProps.put("scooter.home", scooterHome);
allProps.put("webapps.path", webappsPath);
allProps.put("app.path", webappPath);
allProps.put("app.name", appName);
String templateRoot = scooterHome + File.separator +
"source" + File.separator +
"templates";
if ((useImplicitAppName && (args.length < 2))
|| (!useImplicitAppName && (args.length < 3))) {
usage();
return;
}
String[] s3 = getCCM(useImplicitAppName, args);
String connName = s3[0];
String controller = s3[1];
String model = s3[2];
String noenhanceStr = System.getProperty("noenhance");
boolean enhance = ("".equals(noenhanceStr))?false:true;
String table = System.getProperty("table");
String typeName = getTypeName(useImplicitAppName, args);
if ("scaffold".equals(typeName)) {
//generate application controller
String cagPath = templateRoot + File.separator +
"controller" + File.separator +
"ApplicationController.tmpl";
Generator cag = new ControllerApplicationGenerator(cagPath, allProps);
cag.generate(false);
//generate controller
String csgPath = templateRoot + File.separator +
"controller" + File.separator +
"ControllerScaffold.tmpl";
Generator csg = new ControllerScaffoldGenerator(csgPath, allProps, connName, controller, model, table);
csg.generate();
String cstgPath = templateRoot + File.separator +
"controller" + File.separator +
"ControllerScaffoldTest.tmpl";
Generator cstg = new ControllerScaffoldTestGenerator(cstgPath, allProps, connName, controller, model, table);
cstg.generate();
//generate model
if (!enhance) {
String mgPath = templateRoot + File.separator +
"model" + File.separator +
"ModelHelper.tmpl";
Generator mcg = new ModelHelperGenerator(mgPath, allProps, connName, model, table, enhance);
mcg.generate();
}
String mgPath = templateRoot + File.separator +
"model" + File.separator +
"Model.tmpl";
Generator mg = new ModelGenerator(mgPath, allProps, connName, model, table, enhance);
mg.generate();
String mtgPath = templateRoot + File.separator +
"model" + File.separator +
"ModelTest.tmpl";
Generator mtg = new ModelTestGenerator(mtgPath, allProps, connName, model, table, enhance);
mtg.generate();
//generate views
String vigPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold" + File.separator +
"index.tmpl";
Generator vig = new ViewIndexGenerator(vigPath, allProps, connName, controller, model, table);
vig.generate();
String vsgPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold" + File.separator +
"show.tmpl";
Generator vsg = new ViewShowGenerator(vsgPath, allProps, connName, controller, model, table);
vsg.generate();
String vagPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold" + File.separator +
"add.tmpl";
Generator vag = new ViewAddGenerator(vagPath, allProps, connName, controller, model, table);
vag.generate();
String vegPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold" + File.separator +
"edit.tmpl";
Generator veg = new ViewEditGenerator(vegPath, allProps, connName, controller, model, table);
veg.generate();
String vpgPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold" + File.separator +
"paged_list.tmpl";
Generator vpg = new ViewPagedGenerator(vpgPath, allProps, connName, controller, model, table);
vpg.generate();
//update resources
Generator rg = new ResourceGenerator(allProps, controller);
rg.generate();
} else if ("scaffold-ajax".equals(typeName)) {
//generate application controller
String cagPath = templateRoot + File.separator +
"controller" + File.separator +
"ApplicationController.tmpl";
Generator cag = new ControllerApplicationGenerator(cagPath, allProps);
cag.generate(false);
//generate controller
String csgPath = templateRoot + File.separator +
"controller" + File.separator +
"ControllerScaffoldAjax.tmpl";
Generator csg = new ControllerScaffoldGenerator(csgPath, allProps, connName, controller, model, table);
csg.generate();
String cstgPath = templateRoot + File.separator +
"controller" + File.separator +
"ControllerScaffoldTest.tmpl";
Generator cstg = new ControllerScaffoldTestGenerator(cstgPath, allProps, connName, controller, model, table);
cstg.generate();
//generate model
if (!enhance) {
String mgPath = templateRoot + File.separator +
"model" + File.separator +
"ModelHelper.tmpl";
Generator mcg = new ModelHelperGenerator(mgPath, allProps, connName, model, table, enhance);
mcg.generate();
}
String mgPath = templateRoot + File.separator +
"model" + File.separator +
"Model.tmpl";
Generator mg = new ModelGenerator(mgPath, allProps, connName, model, table, enhance);
mg.generate();
String mtgPath = templateRoot + File.separator +
"model" + File.separator +
"ModelTest.tmpl";
Generator mtg = new ModelTestGenerator(mtgPath, allProps, connName, model, table, enhance);
mtg.generate();
//generate views
String vigPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold-ajax" + File.separator +
"index.tmpl";
Generator vig = new ViewIndexGenerator(vigPath, allProps, connName, controller, model, table);
vig.generate();
String vsgPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold-ajax" + File.separator +
"show.tmpl";
Generator vsg = new ViewShowGenerator(vsgPath, allProps, connName, controller, model, table);
vsg.generate();
String vagPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold-ajax" + File.separator +
"add.tmpl";
Generator vag = new ViewAddGenerator(vagPath, allProps, connName, controller, model, table);
vag.generate();
String vegPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold-ajax" + File.separator +
"edit.tmpl";
Generator veg = new ViewEditGenerator(vegPath, allProps, connName, controller, model, table);
veg.generate();
String vpgPath = templateRoot + File.separator +
"view" + File.separator +
"scaffold-ajax" + File.separator +
"paged_list.tmpl";
Generator vpg = new ViewPagedGenerator(vpgPath, allProps, connName, controller, model, table);
vpg.generate();
//update resources
Generator rg = new ResourceGenerator(allProps, controller);
rg.generate();
}
else if ("controller".equals(typeName)) {
//generate application controller
String cagPath = templateRoot + File.separator +
"controller" + File.separator +
"ApplicationController.tmpl";
Generator cag = new ControllerApplicationGenerator(cagPath, allProps);
cag.generate(false);
controller = getControllerName(useImplicitAppName, args, false);
String[] actions = null;
if (useImplicitAppName) {
if (args.length == 2) {
actions = new String[1];
actions[0] = "index";
}
else {
actions = new String[args.length-2];
System.arraycopy(args, 2, actions, 0, actions.length);
}
}
else {
if (args.length == 3) {
actions = new String[1];
actions[0] = "index";
}
else {
actions = new String[args.length-3];
System.arraycopy(args, 3, actions, 0, actions.length);
}
}
String cgPath = templateRoot + File.separator +
"controller" + File.separator +
"ActionController.tmpl";
Generator cg = new ControllerGenerator(cgPath, allProps, controller, actions);
cg.generate();
String ctgPath = templateRoot + File.separator +
"controller" + File.separator +
"ActionControllerTest.tmpl";
Generator ctg = new ControllerTestGenerator(ctgPath, allProps, controller, actions);
ctg.generate();
//generate view
String vigPath = templateRoot + File.separator +
"view" + File.separator +
"action.tmpl";
int views = actions.length;
Generator vig = null;
for (int i = 0; i < views; i++) {
vig = new ViewActionGenerator(vigPath, allProps, controller, actions[i]);
vig.generate();
}
}
else if ("model".equals(typeName)) {
if (!enhance) {
String mgPath = templateRoot + File.separator +
"model" + File.separator +
"ModelHelper.tmpl";
Generator mcg = new ModelHelperGenerator(mgPath, allProps, connName, model, table, enhance);
mcg.generate();
}
String mgPath = templateRoot + File.separator +
"model" + File.separator +
"Model.tmpl";
Generator mg = new ModelGenerator(mgPath, allProps, connName, model, table, enhance);
mg.generate();
String mtgPath = templateRoot + File.separator +
"model" + File.separator +
"ModelTest.tmpl";
Generator mtg = new ModelTestGenerator(mtgPath, allProps, connName, model, table, enhance);
mtg.generate();
}
else {
throw new Exception("Type name \"" + typeName + "\" is not supported.");
}
}
private static boolean isTypeName(String s) {
s = s.toLowerCase();
return "scaffold".equals(s) || "scaffold-ajax".equals(s) || "controller".equals(s) || "model".equals(s) || "model2".equals(s);
}
private static String getTypeName(boolean useImplicitAppName, String[] args) {
String typeName = (useImplicitAppName)?args[0]:args[1];
if (!isTypeName(typeName)) {
throw new IllegalArgumentException("Type name \"" + typeName + "\" is not supported.");
}
return typeName;
}
private static String getControllerName(boolean useImplicitAppName, String[] args, boolean plural) {
String controllerName = (useImplicitAppName)?args[1]:args[2];
int index = controllerName.indexOf('@');
if (index != -1) {
controllerName = controllerName.substring(0, index);
}
if (plural) controllerName = WordUtil.pluralize(controllerName);
return controllerName;
}
private static String[] getCCM(boolean useImplicitAppName, String[] args) {
String connectionName = null;
String controllerName = null;
String modelName = null;
String s = (useImplicitAppName)?args[1]:args[2];
int index = s.indexOf('@');
if (index != -1) {
String s1 = s.substring(0, index);
String s2 = s.substring(index + 1);
connectionName = s2;
controllerName = s1;
modelName = s1;
}
else {
controllerName = s;
modelName = s;
}
if (controllerName.indexOf('.') != -1) {
controllerName = controllerName.replace('.', '_');
controllerName = WordUtil.camelize(controllerName).toLowerCase();
}
controllerName = WordUtil.pluralize(controllerName);
modelName = enforceSingle(modelName);
String[] s3 = new String[3];
s3[0] = connectionName;
s3[1] = controllerName;
s3[2] = modelName;
return s3;
}
private static String enforceSingle(String word) {
if (word.equals(WordUtil.pluralize(word))) {
String sword = WordUtil.singularize(word);
log(word + " is a plural word. Its singularized form \"" + sword +
"\" is used to generate code. Use \"additional.single.plural\" " +
"property in environment.properties file if you want to use " +
"a different singularized word.");
word = sword;
}
return word;
}
private static void log(Object o) {
System.out.println(o);
}
private static void usage() {
log("Summary:");
log(" This utility generates codes.");
log("");
log("Usage:");
log(" java -jar tools/generate.jar [app_path] scaffold {model_name_in_singular_form}[@connection_name]");
log(" java -jar tools/generate.jar [app_path] scaffold-ajax {model_name_in_singular_form}[@connection_name]");
log(" java -jar tools/generate.jar [app_path] controller controller_name_in_plural_form [method] [method] ...");
log(" java -jar tools/generate.jar [app_path] model {model_name_in_singular_form}[@connection_name]");
log("");
log("Options:");
log(" -Dnoenhance -- Do not allow byte code enhancement. Default is allowed.");
log(" -Dtable=YourTable -- Explicitly specify a table name for the model.");
log("");
log("Examples:");
log(" This page:");
log(" java -jar tools/generate.jar -help");
log("");
log(" Generate scaffold code for blog app's domain named post based on default db connection:");
log(" java -jar tools/generate.jar blog scaffold post");
log("");
log(" Generate ajax scaffold code for blog app's domain named post:");
log(" java -jar tools/generate.jar blog scaffold-ajax post");
log("");
log(" Generate scaffold code for blog app's domain named post based on blog_oracle database:");
log(" java -jar tools/generate.jar blog scaffold post@blog_oracle");
log("");
log(" Generate scaffold code for blog app's domain named post which maps to table message:");
log(" java -Dtable=message -jar tools/generate.jar blog scaffold post");
log("");
log(" Generate scaffold code for blog app's domain named post without allowing enhancement:");
log(" java -Dnoenhance -jar tools/generate.jar blog scaffold post");
log("");
log(" Generate scaffold code of post model for blog app in user home directory:");
log(" java -jar tools/generate.jar /home/john/projects/blog scaffold post");
log("");
log(" Generate scaffold code for blog app's domain named post when blog is the only app under webapps:");
log(" java -jar tools/generate.jar scaffold post");
log("");
log(" Generate controller code for blog app's domain post with index and show actions:");
log(" java -jar tools/generate.jar blog controller posts index show");
log("");
log(" Generate controller code for domain post with index and show actions when blog is the only app under webapps:");
log(" java -jar tools/generate.jar controller posts index show");
log("");
log(" Generate model code for blog app's domain post:");
log(" java -jar tools/generate.jar blog model post");
log("");
log(" Generate model code for domain post when blog is the only app under webapps:");
log(" java -jar tools/generate.jar model post");
log("");
}
}