Java tutorial
/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * 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 com.liferay.blade.cli; 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 com.liferay.blade.cli.gradle.GradleTooling; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.regex.Pattern; import org.apache.commons.lang3.text.WordUtils; /** * @author Gregory Amerson * @author David Truong */ public class CreateCommand { public static final String DESCRIPTION = "Creates a new Liferay module project from several available " + "templates."; public static final List<String> TEMPLATE_NAMES = Arrays.asList("activator", "contenttargetingreport", "contenttargetingrule", "contenttargetingtrackingaction", "controlmenuentry", "fragment", "mvcportlet", "panelapp", "portlet", "portletprovider", "service", "servicebuilder", "servicewrapper"); public static final String TEMPLATES_VERSION = "1.0.13"; private static File zipFile = null; public CreateCommand(blade blade, CreateOptions options) { _blade = blade; _options = options; } public void execute() throws Exception { if (_options.listtemplates()) { listTemplates(); return; } List<String> args = _options._arguments(); String template = _options.template(); if (template == null) { template = "mvcportlet"; } else if (!isExistingTemplate(template)) { addError("Create", "the template " + template + " is not in the list"); return; } String name = args.remove(0); final File dir = _options.dir() != null ? _options.dir() : getDefaultDir(); final File workDir = Processor.getFile(dir, name); if (!checkDir(workDir)) { addError("Create", name + " is not empty or it is a file." + " Please clean or delete it then run again"); return; } final boolean isWorkspace = Util.isWorkspace(dir); name = workDir.getName(); final Pattern glob = Pattern.compile("^standalone/" + template + "/.*|\\...+/.*"); final Map<String, String> subs = new HashMap<>(); subs.put("templates/standalone/" + template + "/", ""); subs.put("_project_path_", workDir.getAbsolutePath()); subs.put("_name_", getPackageName(name)); subs.put("_NAME_", name); final String packageName = _options.packagename(); if (isEmpty(packageName)) { subs.put("_package_path_", getPackageName(name).replaceAll("\\.", "/")); subs.put("_package_", getPackageName(name)); } else { subs.put("_package_path_", packageName.replaceAll("\\.", "/")); subs.put("_package_", packageName); } String classname = _options.classname(); if (isEmpty(classname)) { classname = getClassName(name); } String service = _options.service(); if ("service".equals(template)) { if (isEmpty(service)) { addError("Create", "The service template requires the fully qualified name " + "of service must be specified after the service " + "argument.\nFor example: blade create -t service -s " + "com.liferay.portal.kernel.events.LifecycleAction " + "customPreAction"); return; } subs.put("_SERVICE_FULL_", service); subs.put("_SERVICE_SHORT_", service.substring(service.lastIndexOf('.') + 1)); } if ("servicewrapper".equals(template)) { if (isEmpty(service)) { addError("Create", "The servicewrapper template requires the fully qualified" + " name of service must be specified after the service" + " argument.\nFor example: blade create -t " + "servicewrapper -s " + "com.liferay.portal.service.UserLocalServiceWrapper " + "customServiceWrapper"); return; } subs.put("_SERVICE_FULL_", service); subs.put("_SERVICE_SHORT_", service.substring(service.lastIndexOf('.') + 1)); } if ("servicebuilder".equals(template)) { if (isEmpty(packageName)) { addError("Create", "The servicebuilder template requires the name of the " + "root package within which to create service builder " + "classes must be specified.\nFor example: blade " + "create -t servicebuilder -p " + "com.liferay.guestbook guestbook"); return; } if (name.indexOf(".") > -1) { subs.put("_api_", packageName + ".api"); subs.put("_service_", packageName + ".svc"); subs.put("_web_", packageName + ".web"); } else { subs.put("_api_", name + "-api"); subs.put("_service_", name + "-service"); subs.put("_web_", name + "-web"); } if (isWorkspace) { final Path workspacePath = Util.getWorkspaceDir(dir).getAbsoluteFile().toPath(); final Path dirPath = dir.getAbsoluteFile().toPath(); final String relativePath = workspacePath.relativize(dirPath).toString(); final String apiPath = ":" + relativePath.replaceAll("\\\\", "/").replaceAll("\\/", ":") + ":" + name; subs.put("_api_path_", apiPath); } else { subs.put("_api_path_", ""); } subs.put("_portlet_", packageName + ".portlet"); subs.put("_portletpackage_", packageName.replaceAll("\\.", "/") + "/portlet"); } else if ("activator".equals(template)) { if (!classname.contains("Activator")) { classname += "Activator"; } } if ("portlet".equals(template) || "mvcportlet".equals(template)) { if (classname.endsWith("Portlet")) { classname = classname.replaceAll("Portlet$", ""); } } final String hostbundlebsn = _options.hostbundlebsn(); final String hostbundleversion = _options.hostbundleversion(); if ("fragment".equals(template)) { if (isEmpty(hostbundlebsn) || isEmpty(hostbundleversion)) { addError("Create", "The fragment template requires the bundle symbolic name " + "of the hostbundle and version must be specified.\n" + "For example: blade create -t fragment -h " + "com.liferay.login.web -H 1.0.0 name"); return; } subs.put("_HOST_BUNDLE_BSN_", hostbundlebsn); subs.put("_HOST_BUNDLE_VERSION_", hostbundleversion); } subs.put("_CLASS_", classname); String unNormalizedPortletFqn = name.toLowerCase().replaceAll("-", ".") + "_" + classname; subs.put("_portlet_fqn_", unNormalizedPortletFqn.replaceAll("\\.", "_")); File moduleTemplatesZip = getGradleTemplatesZip(); InputStream in = new FileInputStream(moduleTemplatesZip); copy("standalone", template, workDir, in, glob, true, subs); in.close(); if (isWorkspace) { final Pattern buildGlob = Pattern.compile("^workspace/" + template + "/.*|\\...+/.*"); in = new FileInputStream(moduleTemplatesZip); copy("workspace", template, workDir, in, buildGlob, true, subs); in.close(); File settingsFile = new File(workDir, "settings.gradle"); if (settingsFile.exists()) { settingsFile.delete(); } IO.delete(new File(workDir, "gradlew")); IO.delete(new File(workDir, "gradlew.bat")); IO.delete(new File(workDir, "gradle")); } else { File gradlew = new File(workDir, "gradlew"); if (gradlew.exists()) { gradlew.setExecutable(true); } } _blade.out().println("Created the project " + name + " using the " + template + " template in " + workDir); } @Arguments(arg = { "[name]" }) @Description(DESCRIPTION) public interface CreateOptions 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("The directory where to create the new project.") public File dir(); @Description("If a new jsp hook fragment needs to be created, provide the name" + " of the host bundle symbolic name.") public String hostbundlebsn(); @Description("If a new jsp hook fragment needs to be created, provide the name" + " of the host bundle version.") public String hostbundleversion(); @Description("Prints a list of available project templates") public boolean listtemplates(); public String packagename(); @Description("If a new DS component needs to be created, provide the name of " + "the service to be implemented.") public String service(); @Description("The project template to use when creating the project. To " + "see the list of templates available use blade create <-l | " + "--listtemplates>") public String template(); } File getGradleTemplatesZip() throws Exception { if (zipFile != null) { return zipFile; } trace("Connecting to repository to find version " + TEMPLATES_VERSION + " gradle templates."); zipFile = GradleTooling.findLatestAvailableArtifact("group: 'com.liferay', " + "name: 'com.liferay.gradle.templates', " + "version: '" + TEMPLATES_VERSION + "', ext: 'jar'"); trace("Found gradle templates " + zipFile); return zipFile; } private void addError(String prefix, String msg) { _blade.addErrors(prefix, Collections.singleton(msg)); } private boolean containsDir(File currentDir, File parentDir) throws Exception { String currentPath = currentDir.getCanonicalPath(); String parentPath = parentDir.getCanonicalPath(); return currentPath.startsWith(parentPath); } private boolean checkDir(File file) { if (file.exists()) { if (!file.isDirectory()) { return false; } else { File[] children = file.listFiles(); if (children != null && children.length > 0) { return false; } } } return true; } private void copy(String type, String template, File workspaceDir, InputStream in, Pattern glob, boolean overwrite, Map<String, String> subs) throws Exception { try (Jar jar = new Jar("dot", in)) { for (Entry<String, Resource> e : jar.getResources().entrySet()) { String path = e.getKey(); 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(type + "/" + template + "/", ""); File dest = Processor.getFile(workspaceDir, path); if (overwrite || (dest.lastModified() < r.lastModified()) || (r.lastModified() <= 0)) { File dp = dest.getParentFile(); if (!dp.exists() && !dp.mkdirs()) { throw new Exception("Could not create directory " + dp); } IO.copy(r.openInputStream(), dest); if (isTextFile(dest)) { process(dest, subs); } } } } } private String getClassName(String name) { name = WordUtils.capitalizeFully(name, ' ', '.', '-'); name = name.replaceAll("[- .]", ""); return name; } private File getDefaultDir() throws Exception { File baseDir = _blade.getBase(); if (!Util.isWorkspace(baseDir)) { return baseDir; } Properties properties = Util.getGradleProperties(baseDir); String modulesDirValue = (String) properties.get(Workspace.DEFAULT_MODULES_DIR_PROPERTY); if (modulesDirValue == null) { modulesDirValue = Workspace.DEFAULT_MODULES_DIR; } File projectDir = Util.getWorkspaceDir(_blade); File modulesDir = new File(projectDir, modulesDirValue); return containsDir(baseDir, modulesDir) ? baseDir : modulesDir; } private String getPackageName(String name) { name = name.replaceAll("[- .]", "."); name = name.toLowerCase(); return name; } private List<String> getTemplates() throws Exception { List<String> templateNames = new ArrayList<>(); File templatesZip = getGradleTemplatesZip(); try (Jar jar = new Jar(templatesZip)) { Map<String, Map<String, Resource>> directories = jar.getDirectories(); for (String key : directories.keySet()) { Path path = Paths.get(key); if (path.getNameCount() == 2 && path.startsWith("standalone")) { templateNames.add(path.getName(1).toString()); } } } return templateNames; } private List<String> getTemplateNames() { return TEMPLATE_NAMES; } private boolean isEmpty(String str) { if (str == null) { return true; } if (str.trim().isEmpty()) { return true; } return false; } private boolean isExistingTemplate(String templateName) throws Exception { List<String> templates = getTemplates(); for (String template : templates) { if (templateName.equals(template)) { return true; } } return false; } private boolean isTextFile(File dest) { String name = dest.getName(); int index = name.lastIndexOf("."); if (index > -1) { return textExtensions.contains(name.substring(index, name.length())); } return false; } private void listTemplates() throws Exception { List<String> templateNames = getTemplateNames(); for (String name : templateNames) { _blade.out().println(name); } } 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 void trace(String msg) { _blade.trace("%s: %s", "create", msg); } private static final List<String> textExtensions = Arrays.asList(".bnd", ".java", ".project", ".xml", ".jsp", ".css", ".jspf", ".js", ".properties", ".gradle", ".prefs"); private final blade _blade; private final CreateOptions _options; }