package org.springframework.roo.addon.web.mvc.thymeleaf.addon;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Service;
import org.osgi.service.component.ComponentContext;
import org.springframework.roo.addon.web.mvc.controller.addon.responses.ControllerMVCResponseService;
import org.springframework.roo.addon.web.mvc.i18n.I18nOperations;
import org.springframework.roo.addon.web.mvc.i18n.languages.EnglishLanguage;
import org.springframework.roo.addon.web.mvc.views.ViewContext;
import org.springframework.roo.application.config.ApplicationConfigService;
import org.springframework.roo.classpath.PhysicalTypeCategory;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.TypeLocationService;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.operations.AbstractOperations;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.model.RooJavaType;
import org.springframework.roo.project.Dependency;
import org.springframework.roo.project.FeatureNames;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.Path;
import org.springframework.roo.project.PathResolver;
import org.springframework.roo.project.ProjectOperations;
import org.springframework.roo.project.Property;
import org.springframework.roo.project.maven.Pom;
import org.springframework.roo.support.osgi.ServiceInstaceManager;
import org.springframework.roo.support.util.FileUtils;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
/**
* Implementation of ControllerMVCResponseService that provides
* Thymeleaf Response types.
*
* With this implementation, Spring Roo will be able to provide Thymeleaf response
* types during controller generations.
*
* @author Juan Carlos GarcĂa
* @since 2.0
*/
@Component
@Service
public class ThymeleafMVCViewResponseService extends AbstractOperations implements
ControllerMVCResponseService {
private static final String RESPONSE_TYPE = "THYMELEAF";
private static final String CONTROLLER_NAME_MODIFIER = "Thymeleaf";
private static final String SPRING_MESSAGES_ENCODING = "spring.messages.encoding";
private static final String SPRING_MESSAGES_ENCODING_VALUE = "ISO-8859-1";
private static final String SPRING_THYMELEAF_MODE = "spring.thymeleaf.mode";
private static final String SPRING_THYMELEAF_MODE_VALUE = "html";
private static final Property DYNAMIC_JASPER_VERSION_PROPERTY = new Property(
"dynamicjasper.version", "5.0.11");
private static final Property DYNAMIC_JASPER_FONTS_VERSION_PROPERTY = new Property(
"dynamicjasper-fonts.version", "1.0");
private static final String DYNAMIC_JASPER_VERSION_PROPERTY_NAME = "${dynamicjasper.version}";
private static final String DYNAMIC_JASPER_FONTS_VERSION_PROPERTY_NAME =
"${dynamicjasper-fonts.version}";
private static final Dependency STARTER_THYMELEAF_DEPENDENCY = new Dependency(
"org.springframework.boot", "spring-boot-starter-thymeleaf", null);
private static final Dependency LAYOUT_THYMELEAF_DEPENDENCY = new Dependency(
"nz.net.ultraq.thymeleaf", "thymeleaf-layout-dialect", null);
private static final Dependency DATA_THYMELEAF_DEPENDENCY = new Dependency(
"com.github.mxab.thymeleaf.extras", "thymeleaf-extras-data-attribute",
"${thymeleaf-data-dialect.version}");
private static final Dependency DYNAMIC_JASPER_DEPENDENCY = new Dependency("ar.com.fdvs",
"DynamicJasper", DYNAMIC_JASPER_VERSION_PROPERTY_NAME);
private static final Dependency DYNAMIC_JASPER_CORE_FONTS_DEPENDENCY = new Dependency(
"ar.com.fdvs", "DynamicJasper-core-fonts", DYNAMIC_JASPER_FONTS_VERSION_PROPERTY_NAME);
private static final Dependency POI_DEPENDENCY = new Dependency("org.apache.poi", "poi", null);
private static final Dependency SPRING_CONTEXT_SUPPORT = new Dependency("org.springframework",
"spring-context-support", null);
private ServiceInstaceManager serviceInstaceManager = new ServiceInstaceManager();
@Override
protected void activate(final ComponentContext cContext) {
super.activate(cContext);
context = cContext.getBundleContext();
serviceInstaceManager.activate(context);
}
/**
* This operation returns the Feature name. In this case,
* the Feature name is the same as the response type.
*
* @return String with TYHMELEAF as Feature name
*/
@Override
public String getName() {
return getResponseType();
}
/**
* This operation checks if this feature is installed in module.
* THYMELEAF is installed in module if thymeleaf dependencies has been installed before.
*
* @return true if thymeleaf dependencies has been installed, if not return false.
*/
@Override
public boolean isInstalledInModule(String moduleName) {
// THYMELEAF is installed if Spring MVC has been installed and Thymeleaf
// dependencies has been installed.
return getProjectOperations().isFeatureInstalled(FeatureNames.MVC)
&& hasThymeleafDependencies(moduleName);
}
/**
* This operation returns the THYMELEAF response type.
*
* @return String with THYMELEAF as response type
*/
@Override
public String getResponseType() {
return RESPONSE_TYPE;
}
/**
* This operation returns the annotation type @RooThymeleaf
*
* @return JavaType with the THYMELEAF annotation type
*/
@Override
public JavaType getAnnotation() {
// Generating @RooThymeleaf annotation
return RooJavaType.ROO_THYMELEAF;
}
/**
* This operation annotates a controller with the THYMELEAF annotation
*
* @param controller JavaType with the controller to be annotated.
*/
@Override
public void annotate(JavaType controller) {
Validate.notNull(controller, "ERROR: You must provide a valid controller");
ClassOrInterfaceTypeDetails controllerDetails =
getTypeLocationService().getTypeDetails(controller);
// Check if provided controller exists on current project
Validate.notNull(controllerDetails, "ERROR: You must provide an existing controller");
// Check if provided controller has been annotated with @RooController
Validate.notNull(controllerDetails.getAnnotation(RooJavaType.ROO_CONTROLLER),
"ERROR: You must provide a controller annotated with @RooController");
// Add Thymeleaf annotation
ClassOrInterfaceTypeDetailsBuilder typeBuilder =
new ClassOrInterfaceTypeDetailsBuilder(controllerDetails);
typeBuilder.addAnnotation(new AnnotationMetadataBuilder(getAnnotation()));
// Write changes on provided controller
getTypeManagementService().createOrUpdateTypeOnDisk(typeBuilder.build());
}
/**
* This operation will check if some controller has the @RooThymeleaf annotation
*
* @param controller JavaType with controller to check
* @return true if provided controller has the THYMELEAF responseType.
* If not, return false.
*/
@Override
public boolean hasResponseType(JavaType controller) {
Validate.notNull(controller, "ERROR: You must provide a valid controller");
ClassOrInterfaceTypeDetails controllerDetails =
getTypeLocationService().getTypeDetails(controller);
if (controllerDetails == null) {
return false;
}
return controllerDetails.getAnnotation(getAnnotation()) != null;
}
@Override
public void install(Pom module) {
// Is necessary to install thymeleaf dependencies
addThymeleafDependencies(module);
// Add JasperReport dependencies
addJasperReportsDependencies(module);
// Add JasperReport export classes
addJasperReportExportClasses(module);
// Is necessary to generate the main controller
addMainController(module);
// Thymeleaf needs Datatables component to list
// data, so is necessary to install Datatables resources
addThymeleafDatatablesResources(module);
// Is necessary to copy static resources
copyStaticResources(module);
// Add application properties
addApplicationProperties(module);
// Add all available WebJar containing required static resources
addWebJars(module);
// Delegate on view generation to create view elements
ViewContext<ThymeleafMetadata> ctx = new ViewContext<ThymeleafMetadata>();
ctx.setProjectName(getProjectOperations().getProjectName(""));
ctx.setVersion(getProjectOperations().getPomFromModuleName("").getVersion());
getViewGenerationService().addIndexView(module.getModuleName(), ctx);
getViewGenerationService().addLoginView(module.getModuleName(), ctx);
getViewGenerationService().addErrorView(module.getModuleName(), ctx);
getViewGenerationService().addDefaultLayout(module.getModuleName(), ctx);
getViewGenerationService().addDefaultLayoutNoMenu(module.getModuleName(), ctx);
getViewGenerationService().addHomeLayout(module.getModuleName(), ctx);
getViewGenerationService().addDefaultListLayout(module.getModuleName(), ctx);
getViewGenerationService().addFooter(module.getModuleName(), ctx);
getViewGenerationService().addHeader(module.getModuleName(), ctx);
getViewGenerationService().addMenu(module.getModuleName(), ctx);
getViewGenerationService().addModal(module.getModuleName(), ctx);
getViewGenerationService().addModalConfirm(module.getModuleName(), ctx);
getViewGenerationService().addModalConfirmDelete(module.getModuleName(), ctx);
getViewGenerationService().addModalExportEmptyError(module.getModuleName(), ctx);
getViewGenerationService().addModalConfirmDeleteBatch(module.getModuleName(), ctx);
getViewGenerationService().addSessionLinks(module.getModuleName(), ctx);
getViewGenerationService().addLanguages(module.getModuleName(), ctx);
getViewGenerationService().addAccessibilityView(module.getModuleName(), ctx);
getViewGenerationService().addDefaultLayoutNoMenu(module.getModuleName(), ctx);
// Add i18n support for english language and use it as default
getI18nOperations().installLanguage(new EnglishLanguage(), true, module);
}
/**
* This operation returns the annotation type that identifies the main
* controller generated by THYMELEAF response type.
*
* @return JavaType with the annotation managed by the implementation.
* This method never returns null.
*
*/
@Override
public JavaType getMainControllerAnnotation() {
// Provides @RooThymeleafMainController
return RooJavaType.ROO_THYMELEAF_MAIN_CONTROLLER;
}
/**
* This operation returns the main controller generated by THYMELEAF response type.
*
*
* @return JavaType with the main controller generated by the implementation.
* Maybe returns null if main controller has not been generated yet.
*/
@Override
public JavaType getMainController() {
Set<ClassOrInterfaceTypeDetails> mainController =
getTypeLocationService().findClassesOrInterfaceDetailsWithAnnotation(
getMainControllerAnnotation());
if (mainController != null && !mainController.isEmpty()) {
Iterator<ClassOrInterfaceTypeDetails> it = mainController.iterator();
while (it.hasNext()) {
return it.next().getType();
}
}
return null;
}
/**
* This method adds JasperReports dependencies to generated project
*
* @param module
*/
private void addJasperReportsDependencies(Pom module) {
String moduleName = module.getModuleName();
// Add Dynamic Jasper dependencies
getProjectOperations().addDependency(moduleName, DYNAMIC_JASPER_DEPENDENCY);
getProjectOperations().addDependency(moduleName, DYNAMIC_JASPER_CORE_FONTS_DEPENDENCY);
// Add Apache POI dependency
getProjectOperations().addDependency(moduleName, POI_DEPENDENCY);
// Add Spring Context Support dependency
getProjectOperations().addDependency(moduleName, SPRING_CONTEXT_SUPPORT);
// Add version properties
getProjectOperations().addProperty("", DYNAMIC_JASPER_VERSION_PROPERTY);
getProjectOperations().addProperty("", DYNAMIC_JASPER_FONTS_VERSION_PROPERTY);
}
/**
* Create the support classes to allow export data to different file
* types using JasperReports.
*
* @param module the Pom from module where classes should be created.
*/
private void addJasperReportExportClasses(Pom module) {
// Create the interface
createJasperReportsClassFromTemplate(module, "JasperReportsExporter-template._java",
"JasperReportsExporter");
// Create one implementation for each type of data
createJasperReportsClassFromTemplate(module, "JasperReportsCsvExporter-template._java",
"JasperReportsCsvExporter");
createJasperReportsClassFromTemplate(module, "JasperReportsPdfExporter-template._java",
"JasperReportsPdfExporter");
createJasperReportsClassFromTemplate(module, "JasperReportsXlsExporter-template._java",
"JasperReportsXlsExporter");
// Add ExportingErrorException
createJasperReportsClassFromTemplate(module, "ExportingErrorException-template._java",
"ExportingErrorException");
}
/**
* This method add new MainController.java class annotated
* with @RooThymeleafMainController
*
* This controller will be used to return index page.
*
* @param module
*/
private void addMainController(Pom module) {
// Check if already exists other main controller annotated with @RooThymeleafMainController
if (getMainController() != null) {
return;
}
// If not, define new JavaType
JavaType mainController =
new JavaType(String.format("%s.web.MainController", getProjectOperations()
.getTopLevelPackage(module.getModuleName())), module.getModuleName());
// Check that new JavaType doesn't exists
ClassOrInterfaceTypeDetails mainControllerDetails =
getTypeLocationService().getTypeDetails(mainController);
if (mainControllerDetails != null) {
AnnotationMetadata mainControllerThymeleafAnnotation =
mainControllerDetails.getAnnotation(getMainControllerAnnotation());
// Maybe, this controller already exists
if (mainControllerThymeleafAnnotation != null) {
return;
} else {
throw new RuntimeException(
"ERROR: You are trying to generate more than one MainController.");
}
}
ClassOrInterfaceTypeDetailsBuilder cidBuilder = null;
final LogicalPath controllerPath =
getPathResolver().getPath(mainController.getModule(), Path.SRC_MAIN_JAVA);
final String resourceIdentifier =
getTypeLocationService().getPhysicalTypeCanonicalPath(mainController, controllerPath);
final String declaredByMetadataId =
PhysicalTypeIdentifier.createIdentifier(mainController,
getPathResolver().getPath(resourceIdentifier));
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
annotations.add(new AnnotationMetadataBuilder(getMainControllerAnnotation()));
cidBuilder =
new ClassOrInterfaceTypeDetailsBuilder(declaredByMetadataId, Modifier.PUBLIC,
mainController, PhysicalTypeCategory.CLASS);
cidBuilder.setAnnotations(annotations);
getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilder.build());
}
/**
* This method adds two spring properties. One of them specifies HTML as the
* template mode to use by Thymeleaf for all existing profiles and the other
* one specifies the messages files encoding as ISO-8859-1.
*
* @param module
*/
private void addApplicationProperties(Pom module) {
List<String> applicationProfiles =
getApplicationConfigService().getApplicationProfiles(module.getModuleName());
for (String profile : applicationProfiles) {
getApplicationConfigService().addProperty(module.getModuleName(), SPRING_THYMELEAF_MODE,
SPRING_THYMELEAF_MODE_VALUE, profile, false);
}
getApplicationConfigService().addProperty(module.getModuleName(), SPRING_MESSAGES_ENCODING,
SPRING_MESSAGES_ENCODING_VALUE, "", false);
}
/**
* This method adds necessary thymeleaf dependencies to
* generated project
*
* @param module
*/
private void addThymeleafDependencies(Pom module) {
// Add Thymeleaf starter
getProjectOperations().addDependency(module.getModuleName(), STARTER_THYMELEAF_DEPENDENCY);
// Add Thymeleaf layout dialect
getProjectOperations().addDependency(module.getModuleName(), LAYOUT_THYMELEAF_DEPENDENCY);
// Add Thymeleaf data dialect
getProjectOperations().addDependency(module.getModuleName(), DATA_THYMELEAF_DEPENDENCY);
// ROO-3813: Use Thymeleaf 3.0 instead of the provided version by Spring IO
// More info about Thymelead 3.0 using Spring Boot here
// http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-use-thymeleaf-3
getProjectOperations().addProperty("", new Property("thymeleaf.version", "3.0.0.RELEASE"));
getProjectOperations().addProperty("",
new Property("thymeleaf-layout-dialect.version", "2.0.0"));
getProjectOperations().addProperty("", new Property("thymeleaf-data-dialect.version", "2.0.1"));
}
/**
* This method install Datatables resources and Datatables support for thymeleaf
* implementation
*
* This is necessary because THYMELEAF response type uses Datatables components to
* list results on generated views.
*
* @param module
*/
private void addThymeleafDatatablesResources(Pom module) {
// Add WebMVCThymeleafUIConfiguration config class
addWebMVCThymeleafUIConfiguration(module);
}
/**
* Configure WebJar dependencies in required pom's.
*
* @param module the module where Thymeleaf is going to be installed
*/
private void addWebJars(Pom module) {
String rootModuleName = "";
List<Dependency> dependencies = new ArrayList<Dependency>();
// Add WebJar locator dependency
dependencies.add(new Dependency("org.webjars", "webjars-locator", null));
//Add Bootstrap WebJar
getProjectOperations().addProperty(rootModuleName, new Property("bootstrap.version", "3.3.6"));
dependencies.add(new Dependency("org.webjars.bower", "bootstrap", "${bootstrap.version}"));
// Add Datatables and Datatables related WebJars
getProjectOperations().addProperty(rootModuleName,
new Property("datatables.version", "1.10.12"));
dependencies.add(new Dependency("org.webjars.bower", "datatables", "${datatables.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-bs.version", "1.10.11"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-bs",
"${datatables-bs.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-buttons.version", "1.1.2"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-buttons",
"${datatables-buttons.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-buttons-bs.version", "1.1.2"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-buttons-bs",
"${datatables-buttons-bs.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-responsive.version", "2.0.2"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-responsive",
"${datatables-responsive.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-responsive-bs.version", "2.0.2"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-responsive-bs",
"${datatables-responsive-bs.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-select.version", "1.1.2"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-select",
"${datatables-select.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-select-bs.version", "1.1.2"));
dependencies.add(new Dependency("org.webjars.bower", "datatables.net-select-bs",
"${datatables-select-bs.version}"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-checkboxes.version", "1.1.2"));
getProjectOperations().addProperty(rootModuleName,
new Property("datatables-mark.version", "2.0.0"));
// Add exclusions to avoid conflicts with Bower dependencies
List<Dependency> exclusions = new ArrayList<Dependency>();
exclusions.add(new Dependency("org.webjars.npm", "jquery", null));
exclusions.add(new Dependency("org.webjars.npm", "datatables.net", null));
dependencies.add(new Dependency("org.webjars.npm", "jquery-datatables-checkboxes",
"${datatables-checkboxes.version}", exclusions));
// Add Datatables mark WebJar
dependencies.add(new Dependency("org.webjars.bower", "github-com-julmot-datatables-mark-js",
"${datatables-mark.version}"));
// Add DatetimePicker WebJar
getProjectOperations().addProperty(rootModuleName,
new Property("datetimepicker.version", "2.5.4"));
dependencies.add(new Dependency("org.webjars.bower", "datetimepicker",
"${datetimepicker.version}"));
// Add FontAwesome WebJar
getProjectOperations()
.addProperty(rootModuleName, new Property("fontawesome.version", "4.6.2"));
dependencies.add(new Dependency("org.webjars.bower", "font-awesome", "${fontawesome.version}"));
// Add jQuery WebJar
getProjectOperations().addProperty(rootModuleName, new Property("jquery.version", "1.12.3"));
dependencies.add(new Dependency("org.webjars.bower", "jquery", "${jquery.version}"));
// Add jQuery InputMask WebJar
getProjectOperations().addProperty(rootModuleName,
new Property("jquery-inputmask.version", "3.3.1"));
// Add exclusions to avoid conflicts with Bower dependencies
exclusions = new ArrayList<Dependency>();
exclusions.add(new Dependency("org.webjars", "jquery", null));
dependencies.add(new Dependency("org.webjars", "jquery.inputmask",
"${jquery-inputmask.version}", exclusions));
// Add jQuery InputMask WebJar
getProjectOperations().addProperty(rootModuleName,
new Property("jquery-validation.version", "1.15.0"));
dependencies.add(new Dependency("org.webjars.bower", "jquery-validation",
"${jquery-validation.version}"));
// Add MomentJS WebJar
getProjectOperations().addProperty(rootModuleName, new Property("momentjs.version", "2.13.0"));
dependencies.add(new Dependency("org.webjars.bower", "momentjs", "${momentjs.version}"));
// Add Select2 WebJar
getProjectOperations().addProperty(rootModuleName, new Property("select2.version", "4.0.3"));
dependencies.add(new Dependency("org.webjars.bower", "select2", "${select2.version}"));
// Add Select2 Bootstrap Theme WebJar
getProjectOperations().addProperty(rootModuleName,
new Property("select2-bootstrap-theme.version", "0.1.0-beta.7"));
dependencies.add(new Dependency("org.webjars.bower", "select2-bootstrap-theme",
"${select2-bootstrap-theme.version}"));
// Add respond WebJar
getProjectOperations().addProperty(rootModuleName, new Property("respond.version", "1.4.2"));
dependencies.add(new Dependency("org.webjars", "respond", "${respond.version}"));
// Add html5shiv WebJar
getProjectOperations().addProperty(rootModuleName, new Property("html5shiv.version", "3.7.3"));
dependencies.add(new Dependency("org.webjars", "html5shiv", "${html5shiv.version}"));
// Add ie10-viewport-bug-workaround WebJar
getProjectOperations().addProperty(rootModuleName,
new Property("bootstrap.ie10-viewport-bug-workaround.version", "1.0.3"));
dependencies.add(new Dependency("org.webjars.bower", "ie10-viewport-bug-workaround",
"${bootstrap.ie10-viewport-bug-workaround.version}"));
getProjectOperations().addDependencies(module.getModuleName(), dependencies);
}
/**
* This method adds new WebMVCThymeleafUIConfiguration.java class inside .config
* package of generated project
*
* @param module
*/
private void addWebMVCThymeleafUIConfiguration(Pom module) {
// Obtain the class annotated with @RooWebMvcConfiguration
Set<ClassOrInterfaceTypeDetails> webMvcConfigurationSet =
getTypeLocationService().findClassesOrInterfaceDetailsWithAnnotation(
RooJavaType.ROO_WEB_MVC_CONFIGURATION);
if (webMvcConfigurationSet == null || webMvcConfigurationSet.isEmpty()) {
throw new RuntimeException(String.format(
"ERROR: Can't found configuration class annotated with @%s.",
RooJavaType.ROO_WEB_MVC_CONFIGURATION));
}
ClassOrInterfaceTypeDetails webMvcConfiguration = webMvcConfigurationSet.iterator().next();
// Prevent to include the @RooWebMvcThymeleafUIConfiguration more than once
if (webMvcConfiguration.getAnnotation(RooJavaType.ROO_WEB_MVC_THYMELEAF_UI_CONFIGURATION) == null) {
AnnotationMetadataBuilder thymeleaftConfigurationAnnotation =
new AnnotationMetadataBuilder(RooJavaType.ROO_WEB_MVC_THYMELEAF_UI_CONFIGURATION);
ClassOrInterfaceTypeDetailsBuilder cidBuilder =
new ClassOrInterfaceTypeDetailsBuilder(webMvcConfiguration);;
cidBuilder.addAnnotation(thymeleaftConfigurationAnnotation);
getTypeManagementService().createOrUpdateTypeOnDisk(cidBuilder.build());
}
}
/**
* This method copy and generate all necessary resources to be able
* to use THYMELEAF.
*
* @param module
*/
private void copyStaticResources(Pom module) {
LogicalPath resourcesPath =
LogicalPath.getInstance(Path.SRC_MAIN_RESOURCES, module.getModuleName());
// copy all necessary styles inside SRC_MAIN_RESOURCES/static/public/css
copyDirectoryContents("static/css/*.css",
getPathResolver().getIdentifier(resourcesPath, "/static/public/css"), true);
// copy all necessary fonts inside SRC_MAIN_RESOURCES/static/public/fonts
copyDirectoryContents("static/fonts/*.eot",
getPathResolver().getIdentifier(resourcesPath, "/static/public/fonts"), true);
copyDirectoryContents("static/fonts/*.svg",
getPathResolver().getIdentifier(resourcesPath, "/static/public/fonts"), true);
copyDirectoryContents("static/fonts/*.ttf",
getPathResolver().getIdentifier(resourcesPath, "/static/public/fonts"), true);
copyDirectoryContents("static/fonts/*.woff",
getPathResolver().getIdentifier(resourcesPath, "/static/public/fonts"), true);
copyDirectoryContents("static/fonts/*.woff2",
getPathResolver().getIdentifier(resourcesPath, "/static/public/fonts"), true);
// copy all necessary images inside SRC_MAIN_RESOURCES/static/public/img
copyDirectoryContents("static/img/*.ico",
getPathResolver().getIdentifier(resourcesPath, "/static/public/img"), false);
copyDirectoryContents("static/img/*.jpg",
getPathResolver().getIdentifier(resourcesPath, "/static/public/img"), false);
copyDirectoryContents("static/img/*.png",
getPathResolver().getIdentifier(resourcesPath, "/static/public/img"), false);
copyDirectoryContents("static/img/*.gif",
getPathResolver().getIdentifier(resourcesPath, "/static/public/img"), false);
// copy all necessary scripts inside SRC_MAIN_RESOURCES/static/public/js
copyDirectoryContents("static/js/*.js",
getPathResolver().getIdentifier(resourcesPath, "/static/public/js"), true);
// copy all necessary scripts inside SRC_MAIN_RESOURCES/templates/fragments/js
copyDirectoryContents("templates/fragments/js/*.html",
getPathResolver().getIdentifier(resourcesPath, "/templates/fragments/js"), true);
copyDirectoryContents("templates/fragments/js/*.js",
getPathResolver().getIdentifier(resourcesPath, "/templates/fragments/js"), true);
// copy default JasperReports template
copyDirectoryContents("templates/reports/*.jrxml",
getPathResolver().getIdentifier(resourcesPath, "/templates/reports"), true);
}
/**
* Creates a class from a template, replacing its package.
*
* @param module
* the Pom related to module where the class should be created
* @param templateName
* the String with the template name
* @param className
* the String with the class name to create
*/
public void createJasperReportsClassFromTemplate(Pom module, String templateName, String className) {
// Set package
String packageName =
getProjectOperations().getTopLevelPackage(module.getModuleName())
.getFullyQualifiedPackageName().concat(".web.reports");
// Include implementation of Validator from template
final JavaType type =
new JavaType(String.format("%s.%s", packageName, className), module.getModuleName());
Validate.notNull(type.getModule(),
"ERROR: Module name is required to generate a valid JavaType");
final String identifier =
getPathResolver().getCanonicalPath(type.getModule(), Path.SRC_MAIN_JAVA, type);
InputStream inputStream = null;
// Check first if file exists
if (!this.fileManager.exists(identifier)) {
try {
// Use defined template
inputStream = FileUtils.getInputStream(getClass(), templateName);
String input = IOUtils.toString(inputStream);
// Replacing package
input = input.replace("__PACKAGE__", packageName);
// Creating CollectionValidator
this.fileManager.createOrUpdateTextFileIfRequired(identifier, input, true);
} catch (final IOException e) {
throw new IllegalStateException(String.format("Unable to create '%s'", identifier), e);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
}
/**
* This method checks if THYMELEAF dependencies has been installed before
*
* @param module
* @return
*/
private boolean hasThymeleafDependencies(String moduleName) {
if (!getProjectOperations().getPomFromModuleName(moduleName)
.getDependenciesExcludingVersion(STARTER_THYMELEAF_DEPENDENCY).isEmpty()
&& !getProjectOperations().getPomFromModuleName(moduleName)
.getDependenciesExcludingVersion(LAYOUT_THYMELEAF_DEPENDENCY).isEmpty()) {
return true;
}
return false;
}
// Getting OSGi services
private ApplicationConfigService getApplicationConfigService() {
return serviceInstaceManager.getServiceInstance(this, ApplicationConfigService.class);
}
private ProjectOperations getProjectOperations() {
return serviceInstaceManager.getServiceInstance(this, ProjectOperations.class);
}
private TypeLocationService getTypeLocationService() {
return serviceInstaceManager.getServiceInstance(this, TypeLocationService.class);
}
private TypeManagementService getTypeManagementService() {
return serviceInstaceManager.getServiceInstance(this, TypeManagementService.class);
}
private PathResolver getPathResolver() {
return serviceInstaceManager.getServiceInstance(this, PathResolver.class);
}
private ThymeleafViewGeneratorService getViewGenerationService() {
return serviceInstaceManager.getServiceInstance(this, ThymeleafViewGeneratorService.class);
}
public I18nOperations getI18nOperations() {
return serviceInstaceManager.getServiceInstance(this, I18nOperations.class);
}
@Override
public String getControllerNameModifier() {
return CONTROLLER_NAME_MODIFIER;
}
@Override
public boolean requiresJsonDeserializer() {
return true;
}
@Override
public boolean requiresJsonMixin() {
return true;
}
@Override
public boolean providesViews() {
// Thymeleaf provider uses HTML to represent the information
return true;
}
}