package blade.cli.cmds;
import aQute.bnd.osgi.Jar;
import aQute.bnd.osgi.Processor;
import aQute.bnd.osgi.Resource;
import aQute.lib.getopt.Arguments;
import aQute.lib.getopt.Description;
import aQute.lib.getopt.Options;
import aQute.lib.io.IO;
import blade.cli.CreateOptions;
import blade.cli.blade;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Formatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.apache.commons.lang3.text.WordUtils;
public class CreateCommand {
final private blade blade;
final private CreateOptions options;
final static private List<String> textExtensions =
Arrays.asList(
".bnd", ".java", ".project", ".xml", ".jsp", ".css", ".jspf",
".js", ".properties");
public CreateCommand(blade blade, CreateOptions options) throws Exception {
this.blade = blade;
this.options = options;
String help = options._command().subCmd(options, this);
if (help != null) {
System.out.println(help);
}
}
@Arguments(arg = {"name"})
interface PortletOptions extends Options {
@Description("If a class is generated in the project, " +
"provide the name of the class to be generated." +
" If not provided defaults to Project name.")
public String classname();
}
@Description(value = "Use basic portlet template for new project")
public void _portlet(PortletOptions opts) throws Exception {
List<String> args = opts._arguments();
String name = args.get(0);
String classname = opts.classname();
createFromTemplate(Type.portlet, name, classname, "");
}
@Arguments(arg = {"name"})
interface JSPPortletOptions extends Options {
}
@Description(value = "Use mvcportlet with jsps template for new project")
public void _jspportlet(JSPPortletOptions opts) throws Exception {
List<String> args = opts._arguments();
String name = args.get(0);
createFromTemplate(Type.jspportlet, name, null, "");
}
@Arguments(arg = {"name", "[service]"})
interface ServiceOptions extends Options {
@Description("If a class is generated in the project, " +
"provide the name of the class to be generated." +
" If not provided defaults to Project name.")
public String classname();
}
@Description(value = "Creates a project with a single service component")
public void _service(ServiceOptions opts) throws Exception {
String classname = opts.classname();
List<String> args = opts._arguments();
String name = args.get(0);
String service = args.get(1);
createFromTemplate(Type.service, name, classname, service);
}
@Arguments(arg = {"name", "[service]"})
interface ServiceWrapperOptions extends ServiceOptions {
}
@Description(value = "Creates a project with a single service wrapper component")
public void _servicewrapper(ServiceWrapperOptions opts) throws Exception {
String classname = opts.classname();
List<String> args = opts._arguments();
String name = args.get(0);
String service = args.get(1);
createFromTemplate(Type.servicewrapper, name, classname, service);
}
private void createFromTemplate(Type type, String name, String classname, String service) throws Exception {
File base = blade.getBase();
File dir = options.dir();
File workDir = null;
if (dir != null) {
workDir = Processor.getFile(dir, name);
name = workDir.getName();
base = workDir.getParentFile();
}
else {
workDir = Processor.getFile(base, name);
name = workDir.getName();
base = workDir.getParentFile();
}
workDir.mkdirs();
InputStream in = getClass().getResourceAsStream("/templates.zip");
if (in == null) {
blade.error(
"Cannot find templates in this jar %s", "/templates.zip");
return;
}
Build build = options.build();
if (build == null) {
build = Build.gradle;
}
Pattern glob = Pattern.compile("^" +
build.toString() + "/" + type + "/.*|\\...+/.*");
Map<String, String> subs = new HashMap<>();
subs.put("templates/" + build + "/" + type + "/", "");
subs.put("_name_", name.toLowerCase());
subs.put("_NAME_", WordUtils.capitalize(name));
subs.put("_package_path_", name.replaceAll("\\.", "/"));
subs.put("_package_", name.toLowerCase().replaceAll("-", "."));
if (classname == null) {
classname = WordUtils.capitalize(name);
}
if (Type.service.equals(type)) {
if (service.isEmpty()) {
blade.error(
"if type is service, the fully qualified name of service " +
"must be specified after the service argument.");
printHelp();
return;
}
subs.put("_SERVICE_FULL_", service);
subs.put(
"_SERVICE_SHORT_",
service.substring(service.lastIndexOf('.') + 1));
}
if (Type.servicewrapper.equals(type)) {
if (service.isEmpty()) {
blade.error(
"if type is service, the fully qualified name of service " +
"must be specified after the service argument.");
printHelp();
return;
}
subs.put("_SERVICE_FULL_", service);
subs.put(
"_SERVICE_SHORT_",
service.substring(service.lastIndexOf('.') + 1));
}
else if (Type.portlet.equals(type) || Type.jspportlet.equals(type)) {
if (!classname.contains("Portlet")) {
classname += "Portlet";
}
}
subs.put("_CLASSNAME_", classname);
String unNormalizedPortletFqn =
name.toLowerCase().replaceAll("-", ".") + "_" + classname;
subs.put(
"_portlet_fqn_",
unNormalizedPortletFqn.replaceAll("\\.", "_"));
copy(build, type, workDir, in, glob, true, subs);
}
private void copy(Build build, Type type,
File workspaceDir, InputStream in, Pattern glob, boolean overwrite,
Map<String, String> subs) throws Exception {
blade.trace("Glob:" + glob);
Jar jar = new Jar("dot", in);
try {
for (Entry<String, Resource> e : jar.getResources().entrySet()) {
String path = e.getKey();
blade.trace(
"path %s matches ? %s : \n", path,
!((glob != null && !glob.matcher(path).matches())));
if (glob != null && !glob.matcher(path).matches())
continue;
Resource r = e.getValue();
for (String key : subs.keySet()) {
path = path.replaceAll(key, subs.get(key));
}
path =
path.replaceAll(build.name() + "/" + type.name() + "/", "");
File dest = Processor.getFile(workspaceDir, path);
blade.trace("Dest Dir:" + path);
if (overwrite ||
dest.lastModified() < r.lastModified() ||
r.lastModified() <= 0) {
blade.trace("copy %s to %s \n", path, dest);
File dp = dest.getParentFile();
if (!dp.exists() && !dp.mkdirs()) {
throw new IOException(
"Could not create directory " + dp);
}
IO.copy(r.openInputStream(), dest);
if (isTextFile(dest)) {
process(dest, subs);
}
}
}
}
finally {
jar.close();
}
}
private void process(File dest, Map<String, String> subs) throws Exception {
String content = new String(IO.read(dest));
String newContent = content;
for (String sub : subs.keySet()) {
newContent = newContent.replaceAll(sub, subs.get(sub));
}
if (!content.equals(newContent)) {
IO.write(newContent.getBytes(), dest);
}
}
private boolean isTextFile(File dest) {
String name = dest.getName();
return textExtensions.contains(
name.substring(name.lastIndexOf("."), name.length()));
}
private void printHelp() throws Exception {
Formatter f = new Formatter();
options._command().help(f, this);
blade.out().println(f);
f.close();
}
}