package org.springframework.roo.addon.web.mvc.jsp;
import static org.springframework.roo.model.SpringJavaType.CONTROLLER;
import static org.springframework.roo.model.SpringJavaType.MODEL_MAP;
import static org.springframework.roo.model.SpringJavaType.PATH_VARIABLE;
import static org.springframework.roo.model.SpringJavaType.REQUEST_MAPPING;
import static org.springframework.roo.model.SpringJavaType.REQUEST_METHOD;
import static org.springframework.roo.project.Path.SRC_MAIN_WEBAPP;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.springframework.roo.addon.backup.BackupOperations;
import org.springframework.roo.addon.propfiles.PropFileOperations;
import org.springframework.roo.addon.web.mvc.controller.WebMvcOperations;
import org.springframework.roo.addon.web.mvc.jsp.i18n.I18n;
import org.springframework.roo.addon.web.mvc.jsp.i18n.I18nSupport;
import org.springframework.roo.addon.web.mvc.jsp.menu.MenuOperations;
import org.springframework.roo.addon.web.mvc.jsp.tiles.TilesOperations;
import org.springframework.roo.classpath.PhysicalTypeCategory;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.TypeManagementService;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.EnumAttributeValue;
import org.springframework.roo.classpath.details.annotations.StringAttributeValue;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.classpath.operations.AbstractOperations;
import org.springframework.roo.model.EnumDetails;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
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.support.osgi.BundleFindingUtils;
import org.springframework.roo.support.util.XmlElementBuilder;
import org.springframework.roo.support.util.XmlUtils;
import org.springframework.roo.uaa.UaaRegistrationService;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
/**
* Implementation of {@link JspOperations}.
*
* @author Stefan Schmidt
* @author Jeremy Grelle
* @since 1.0
*/
@Component
@Service
public class JspOperationsImpl extends AbstractOperations implements
JspOperations {
private static final JavaType HTTP_SERVLET_REQUEST = new JavaType(
"javax.servlet.http.HttpServletRequest");
private static final JavaType HTTP_SERVLET_RESPONSE = new JavaType(
"javax.servlet.http.HttpServletResponse");
/**
* Returns the folder name and mapping value for the given preferred maaping
*
* @param preferredMapping (can be blank)
* @param controller the associated controller type (required)
* @return a non-<code>null</code> pair
*/
static ImmutablePair<String, String> getFolderAndMapping(
final String preferredMapping, final JavaType controller) {
if (StringUtils.isNotBlank(preferredMapping)) {
String folderName = StringUtils.removeStart(preferredMapping, "/");
folderName = StringUtils.removeEnd(folderName, "**");
folderName = StringUtils.removeEnd(folderName, "/");
String mapping = (preferredMapping.startsWith("/") ? "" : "/")
+ preferredMapping;
mapping = StringUtils.removeEnd(mapping, "/");
mapping = mapping + (mapping.endsWith("/**") ? "" : "/**");
return new ImmutablePair<String, String>(folderName, mapping);
}
// Use sensible defaults
final String typeNameLower = StringUtils.removeEnd(
controller.getSimpleTypeName(), "Controller").toLowerCase();
return new ImmutablePair<String, String>(typeNameLower, "/"
+ typeNameLower + "/**");
}
@Reference private BackupOperations backupOperations;
@Reference private I18nSupport i18nSupport;
@Reference private MenuOperations menuOperations;
@Reference private PathResolver pathResolver;
@Reference private ProjectOperations projectOperations;
@Reference private PropFileOperations propFileOperations;
@Reference private TilesOperations tilesOperations;
@Reference private TypeManagementService typeManagementService;
@Reference private UaaRegistrationService uaaRegistrationService;
@Reference private WebMvcOperations webMvcOperations;
private String cleanPath(String path) {
if ("/".equals(path)) {
return "";
}
path = "/" + path;
if (path.contains(".")) {
path = path.substring(0, path.indexOf(".") - 1);
}
return path;
}
private String cleanViewName(String viewName) {
if (viewName.startsWith("/")) {
viewName = viewName.substring(1);
}
if (viewName.contains(".")) {
viewName = viewName.substring(0, viewName.indexOf(".") - 1);
}
return viewName;
}
/**
* Creates a new Spring MVC controller.
* <p>
* Request mappings assigned by this method will always commence with "/"
* and end with "/**". You may present this prefix and/or this suffix if you
* wish, although it will automatically be added should it not be provided.
*
* @param controller the controller class to create (required)
* @param preferredMapping the mapping this controller should adopt
* (optional; if unspecified it will be based on the controller
* name)
*/
public void createManualController(final JavaType controller,
final String preferredMapping, final LogicalPath webappPath) {
Validate.notNull(controller, "Controller Java Type required");
// Create annotation @RequestMapping("/myobject/**")
final ImmutablePair<String, String> folderAndMapping = getFolderAndMapping(
preferredMapping, controller);
final String folderName = folderAndMapping.getKey();
final String resourceIdentifier = pathResolver.getFocusedCanonicalPath(
Path.SRC_MAIN_JAVA, controller);
final String declaredByMetadataId = PhysicalTypeIdentifier
.createIdentifier(controller, projectOperations
.getPathResolver().getPath(resourceIdentifier));
final List<MethodMetadataBuilder> methods = new ArrayList<MethodMetadataBuilder>();
// Add HTTP post method
methods.add(getHttpPostMethod(declaredByMetadataId));
// Add index method
methods.add(getIndexMethod(folderName, declaredByMetadataId));
// Create Type definition
final List<AnnotationMetadataBuilder> typeAnnotations = new ArrayList<AnnotationMetadataBuilder>();
final List<AnnotationAttributeValue<?>> requestMappingAttributes = new ArrayList<AnnotationAttributeValue<?>>();
requestMappingAttributes.add(new StringAttributeValue(
new JavaSymbolName("value"), folderAndMapping.getValue()));
final AnnotationMetadataBuilder requestMapping = new AnnotationMetadataBuilder(
REQUEST_MAPPING, requestMappingAttributes);
typeAnnotations.add(requestMapping);
// Create annotation @Controller
final List<AnnotationAttributeValue<?>> controllerAttributes = new ArrayList<AnnotationAttributeValue<?>>();
final AnnotationMetadataBuilder controllerAnnotation = new AnnotationMetadataBuilder(
CONTROLLER, controllerAttributes);
typeAnnotations.add(controllerAnnotation);
final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(
declaredByMetadataId, Modifier.PUBLIC, controller,
PhysicalTypeCategory.CLASS);
cidBuilder.setAnnotations(typeAnnotations);
cidBuilder.setDeclaredMethods(methods);
typeManagementService.createOrUpdateTypeOnDisk(cidBuilder.build());
installView(
folderName,
"/index",
new JavaSymbolName(controller.getSimpleTypeName())
.getReadableSymbolName() + " View", "Controller", null,
false, webappPath);
}
private MethodMetadataBuilder getHttpPostMethod(
final String declaredByMetadataId) {
final List<AnnotationMetadataBuilder> postMethodAnnotations = new ArrayList<AnnotationMetadataBuilder>();
final List<AnnotationAttributeValue<?>> postMethodAttributes = new ArrayList<AnnotationAttributeValue<?>>();
postMethodAttributes.add(new EnumAttributeValue(new JavaSymbolName(
"method"), new EnumDetails(REQUEST_METHOD, new JavaSymbolName(
"POST"))));
postMethodAttributes.add(new StringAttributeValue(new JavaSymbolName(
"value"), "{id}"));
postMethodAnnotations.add(new AnnotationMetadataBuilder(
REQUEST_MAPPING, postMethodAttributes));
final List<AnnotatedJavaType> postParamTypes = new ArrayList<AnnotatedJavaType>();
final AnnotationMetadataBuilder idParamAnnotation = new AnnotationMetadataBuilder(
PATH_VARIABLE);
postParamTypes.add(new AnnotatedJavaType(
new JavaType("java.lang.Long"), idParamAnnotation.build()));
postParamTypes.add(new AnnotatedJavaType(MODEL_MAP));
postParamTypes.add(new AnnotatedJavaType(HTTP_SERVLET_REQUEST));
postParamTypes.add(new AnnotatedJavaType(HTTP_SERVLET_RESPONSE));
final List<JavaSymbolName> postParamNames = new ArrayList<JavaSymbolName>();
postParamNames.add(new JavaSymbolName("id"));
postParamNames.add(new JavaSymbolName("modelMap"));
postParamNames.add(new JavaSymbolName("request"));
postParamNames.add(new JavaSymbolName("response"));
final MethodMetadataBuilder postMethodBuilder = new MethodMetadataBuilder(
declaredByMetadataId, Modifier.PUBLIC, new JavaSymbolName(
"post"), JavaType.VOID_PRIMITIVE, postParamTypes,
postParamNames, new InvocableMemberBodyBuilder());
postMethodBuilder.setAnnotations(postMethodAnnotations);
return postMethodBuilder;
}
private MethodMetadataBuilder getIndexMethod(final String folderName,
final String declaredByMetadataId) {
final List<AnnotationMetadataBuilder> indexMethodAnnotations = new ArrayList<AnnotationMetadataBuilder>();
indexMethodAnnotations.add(new AnnotationMetadataBuilder(
REQUEST_MAPPING, new ArrayList<AnnotationAttributeValue<?>>()));
final InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder();
bodyBuilder.appendFormalLine("return \"" + folderName + "/index\";");
final MethodMetadataBuilder indexMethodBuilder = new MethodMetadataBuilder(
declaredByMetadataId, Modifier.PUBLIC, new JavaSymbolName(
"index"), JavaType.STRING,
new ArrayList<AnnotatedJavaType>(),
new ArrayList<JavaSymbolName>(), bodyBuilder);
indexMethodBuilder.setAnnotations(indexMethodAnnotations);
return indexMethodBuilder;
}
public String getName() {
return FeatureNames.MVC;
}
public void installCommonViewArtefacts() {
installCommonViewArtefacts(projectOperations.getFocusedModuleName());
}
public void installCommonViewArtefacts(final String moduleName) {
Validate.isTrue(isProjectAvailable(), "Project metadata required");
final LogicalPath webappPath = Path.SRC_MAIN_WEBAPP
.getModulePathId(moduleName);
if (!isControllerAvailable()) {
webMvcOperations.installAllWebMvcArtifacts();
}
// Install tiles config
updateConfiguration();
// Install styles
copyDirectoryContents("images/*.*",
pathResolver.getIdentifier(webappPath, "images"), false);
// Install styles
copyDirectoryContents("styles/*.css",
pathResolver.getIdentifier(webappPath, "styles"), false);
copyDirectoryContents("styles/*.properties",
pathResolver.getIdentifier(webappPath, "WEB-INF/classes"),
false);
// Install layout
copyDirectoryContents("tiles/default.jspx",
pathResolver.getIdentifier(webappPath, "WEB-INF/layouts/"),
false);
copyDirectoryContents("tiles/layouts.xml",
pathResolver.getIdentifier(webappPath, "WEB-INF/layouts/"),
false);
copyDirectoryContents("tiles/header.jspx",
pathResolver.getIdentifier(webappPath, "WEB-INF/views/"), false);
copyDirectoryContents("tiles/menu.jspx",
pathResolver.getIdentifier(webappPath, "WEB-INF/views/"), false);
copyDirectoryContents("tiles/footer.jspx",
pathResolver.getIdentifier(webappPath, "WEB-INF/views/"), false);
copyDirectoryContents("tiles/views.xml",
pathResolver.getIdentifier(webappPath, "WEB-INF/views/"), false);
// Install common view files
copyDirectoryContents("*.jspx",
pathResolver.getIdentifier(webappPath, "WEB-INF/views/"), false);
// Install tags
copyDirectoryContents("tags/form/*.tagx",
pathResolver.getIdentifier(webappPath, "WEB-INF/tags/form"),
false);
copyDirectoryContents("tags/form/fields/*.tagx",
pathResolver.getIdentifier(webappPath,
"WEB-INF/tags/form/fields"), false);
copyDirectoryContents("tags/menu/*.tagx",
pathResolver.getIdentifier(webappPath, "WEB-INF/tags/menu"),
false);
copyDirectoryContents("tags/util/*.tagx",
pathResolver.getIdentifier(webappPath, "WEB-INF/tags/util"),
false);
// Install default language 'en'
installI18n(i18nSupport.getLanguage(Locale.ENGLISH), webappPath);
final String i18nDirectory = pathResolver.getIdentifier(webappPath,
"WEB-INF/i18n/application.properties");
if (!fileManager.exists(i18nDirectory)) {
try {
final String projectName = projectOperations
.getProjectName(projectOperations
.getFocusedModuleName());
fileManager.createFile(pathResolver.getIdentifier(webappPath,
"WEB-INF/i18n/application.properties"));
propFileOperations
.addPropertyIfNotExists(webappPath,
"WEB-INF/i18n/application.properties",
"application_name",
projectName.substring(0, 1).toUpperCase()
+ projectName.substring(1), true);
}
catch (final Exception e) {
throw new IllegalStateException(
"Encountered an error during copying of resources for MVC JSP addon.",
e);
}
}
}
public void installI18n(final I18n i18n, final LogicalPath webappPath) {
Validate.notNull(i18n, "Language choice required");
if (i18n.getLocale() == null) {
LOGGER.warning("could not parse language choice");
return;
}
final String targetDirectory = pathResolver.getIdentifier(webappPath,
"");
// Install message bundle
String messageBundle = targetDirectory + "/WEB-INF/i18n/messages_"
+ i18n.getLocale().getLanguage() /* + country */+ ".properties";
// Special case for english locale (default)
if (i18n.getLocale().equals(Locale.ENGLISH)) {
messageBundle = targetDirectory
+ "/WEB-INF/i18n/messages.properties";
}
if (!fileManager.exists(messageBundle)) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = i18n.getMessageBundle();
outputStream = fileManager.createFile(messageBundle)
.getOutputStream();
IOUtils.copy(inputStream, outputStream);
}
catch (final Exception e) {
throw new IllegalStateException(
"Encountered an error during copying of message bundle MVC JSP addon.",
e);
}
finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
// Install flag
final String flagGraphic = targetDirectory + "/images/"
+ i18n.getLocale().getLanguage() /* + country */+ ".png";
if (!fileManager.exists(flagGraphic)) {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = i18n.getFlagGraphic();
outputStream = fileManager.createFile(flagGraphic)
.getOutputStream();
IOUtils.copy(inputStream, outputStream);
}
catch (final Exception e) {
throw new IllegalStateException(
"Encountered an error during copying of flag graphic for MVC JSP addon.",
e);
}
finally {
IOUtils.closeQuietly(inputStream);
IOUtils.closeQuietly(outputStream);
}
}
// Setup language definition in languages.jspx
final String footerFileLocation = targetDirectory
+ "/WEB-INF/views/footer.jspx";
final Document footer = XmlUtils.readXml(fileManager
.getInputStream(footerFileLocation));
if (XmlUtils.findFirstElement(
"//span[@id='language']/language[@locale='"
+ i18n.getLocale().getLanguage() + "']",
footer.getDocumentElement()) == null) {
final Element span = XmlUtils.findRequiredElement(
"//span[@id='language']", footer.getDocumentElement());
span.appendChild(new XmlElementBuilder("util:language", footer)
.addAttribute("locale", i18n.getLocale().getLanguage())
.addAttribute("label", i18n.getLanguage()).build());
fileManager.createOrUpdateTextFileIfRequired(footerFileLocation,
XmlUtils.nodeToString(footer), false);
}
// Record use of add-on (most languages are implemented via public
// add-ons)
final String bundleSymbolicName = BundleFindingUtils
.findFirstBundleForTypeName(context.getBundleContext(), i18n
.getClass().getName());
if (bundleSymbolicName != null) {
uaaRegistrationService.registerBundleSymbolicNameUse(
bundleSymbolicName, null);
}
}
/**
* Creates a new Spring MVC static view.
*
* @param viewName the bare logical name of the new view (required, e.g.
* "index")
* @param folderName the folder in which to create the view; must be empty
* or start with a slash
* @param title the title
* @param category the menu category in which to list the new view
* (required)
* @param registerStaticController whether to register a static controller
* in the Spring MVC configuration file
*/
private void installView(final JavaSymbolName viewName,
final String folderName, final String title, final String category,
final boolean registerStaticController, final LogicalPath webappPath) {
// Probe if common web artifacts exist, and install them if needed
final PathResolver pathResolver = projectOperations.getPathResolver();
if (!fileManager.exists(pathResolver.getIdentifier(webappPath,
"WEB-INF/layouts/default.jspx"))) {
installCommonViewArtefacts(webappPath.getModule());
}
final String lcViewName = viewName.getSymbolName().toLowerCase();
// Update the application-specific resource bundle (i.e. default
// translation)
final String messageCode = "label"
+ folderName.replace("/", "_").toLowerCase() + "_" + lcViewName;
propFileOperations
.addPropertyIfNotExists(
pathResolver.getFocusedPath(Path.SRC_MAIN_WEBAPP),
"WEB-INF/i18n/application.properties", messageCode,
title, true);
// Add the menu item
final String relativeUrl = folderName + "/" + lcViewName;
menuOperations.addMenuItem(new JavaSymbolName(category),
new JavaSymbolName(folderName.replace("/", "_").toLowerCase()
+ lcViewName + "_id"), title, "global_generic",
relativeUrl, null, webappPath);
// Add the view definition
tilesOperations.addViewDefinition(folderName.toLowerCase(),
pathResolver.getFocusedPath(Path.SRC_MAIN_WEBAPP), relativeUrl,
TilesOperations.DEFAULT_TEMPLATE,
"/WEB-INF/views" + folderName.toLowerCase() + "/" + lcViewName
+ ".jspx");
if (registerStaticController) {
// Update the Spring MVC config file
registerStaticSpringMvcController(relativeUrl, webappPath);
}
}
private void installView(final String path, final String viewName,
final String title, final String category, Document document,
final boolean registerStaticController, final LogicalPath webappPath) {
Validate.notBlank(path, "Path required");
Validate.notBlank(viewName, "View name required");
Validate.notBlank(title, "Title required");
final String cleanedPath = cleanPath(path);
final String cleanedViewName = cleanViewName(viewName);
final String lcViewName = cleanedViewName.toLowerCase();
if (document == null) {
try {
document = getDocumentTemplate("index-template.jspx");
XmlUtils.findRequiredElement("/div/message",
document.getDocumentElement()).setAttribute(
"code",
"label" + cleanedPath.replace("/", "_").toLowerCase()
+ "_" + lcViewName);
}
catch (final Exception e) {
throw new IllegalStateException(
"Encountered an error during copying of resources for controller class.",
e);
}
}
final String viewFile = pathResolver.getFocusedIdentifier(
Path.SRC_MAIN_WEBAPP,
"WEB-INF/views" + cleanedPath.toLowerCase() + "/" + lcViewName
+ ".jspx");
fileManager.createOrUpdateTextFileIfRequired(viewFile,
XmlUtils.nodeToString(document), false);
installView(new JavaSymbolName(lcViewName), cleanedPath, title,
category, registerStaticController, webappPath);
}
public void installView(final String path, final String viewName,
final String title, final String category, final Document document,
final LogicalPath webappPath) {
installView(path, viewName, title, category, document, true, webappPath);
}
public void installView(final String path, final String viewName,
final String title, final String category,
final LogicalPath webappPath) {
installView(path, viewName, title, category, null, true, webappPath);
}
public boolean isControllerAvailable() {
return fileManager.exists(pathResolver.getFocusedIdentifier(
Path.SRC_MAIN_WEBAPP, "WEB-INF/views"))
&& !projectOperations
.isFeatureInstalledInFocusedModule(FeatureNames.JSF);
}
public boolean isInstalledInModule(final String moduleName) {
final LogicalPath webAppPath = LogicalPath.getInstance(
Path.SRC_MAIN_WEBAPP, moduleName);
return fileManager.exists(projectOperations.getPathResolver()
.getIdentifier(webAppPath, "WEB-INF/spring/webmvc-config.xml"));
}
public boolean isInstallLanguageCommandAvailable() {
return isProjectAvailable()
&& fileManager.exists(pathResolver.getFocusedIdentifier(
Path.SRC_MAIN_WEBAPP, "WEB-INF/views/footer.jspx"));
}
public boolean isMvcInstallationPossible() {
return isProjectAvailable()
&& !isControllerAvailable()
&& !projectOperations
.isFeatureInstalledInFocusedModule(FeatureNames.JSF);
}
private boolean isProjectAvailable() {
return projectOperations.isFocusedProjectAvailable();
}
/**
* Registers a static Spring MVC controller to handle the given relative
* URL.
*
* @param relativeUrl the relative URL to handle (required); a leading slash
* will be added if required
*/
private void registerStaticSpringMvcController(final String relativeUrl,
final LogicalPath webappPath) {
final String mvcConfig = projectOperations.getPathResolver()
.getIdentifier(webappPath, "WEB-INF/spring/webmvc-config.xml");
if (fileManager.exists(mvcConfig)) {
final Document document = XmlUtils.readXml(fileManager
.getInputStream(mvcConfig));
final String prefixedUrl = "/" + relativeUrl;
if (XmlUtils.findFirstElement("/beans/view-controller[@path='"
+ prefixedUrl + "']", document.getDocumentElement()) == null) {
final Element sibling = XmlUtils
.findFirstElement("/beans/view-controller",
document.getDocumentElement());
final Element view = new XmlElementBuilder(
"mvc:view-controller", document).addAttribute("path",
prefixedUrl).build();
if (sibling != null) {
sibling.getParentNode().insertBefore(view, sibling);
}
else {
document.getDocumentElement().appendChild(view);
}
fileManager.createOrUpdateTextFileIfRequired(mvcConfig,
XmlUtils.nodeToString(document), false);
}
}
}
/**
* Adds Tiles Maven dependencies and updates the MVC config to include Tiles
* view support
*/
private void updateConfiguration() {
// Add tiles dependencies to pom
final Element configuration = XmlUtils.getRootElement(getClass(),
"tiles/configuration.xml");
final List<Dependency> dependencies = new ArrayList<Dependency>();
final List<Element> springDependencies = XmlUtils.findElements(
"/configuration/tiles/dependencies/dependency", configuration);
for (final Element dependencyElement : springDependencies) {
dependencies.add(new Dependency(dependencyElement));
}
projectOperations.addDependencies(
projectOperations.getFocusedModuleName(), dependencies);
// Add config to MVC app context
final String mvcConfig = pathResolver.getFocusedIdentifier(
SRC_MAIN_WEBAPP, "WEB-INF/spring/webmvc-config.xml");
final Document mvcConfigDocument = XmlUtils.readXml(fileManager
.getInputStream(mvcConfig));
final Element beans = mvcConfigDocument.getDocumentElement();
if (XmlUtils.findFirstElement("/beans/bean[@id = 'tilesViewResolver']",
beans) != null
|| XmlUtils.findFirstElement(
"/beans/bean[@id = 'tilesConfigurer']", beans) != null) {
return; // Tiles is already configured, nothing to do
}
final Document configDoc = getDocumentTemplate("tiles/tiles-mvc-config-template.xml");
final Element configElement = configDoc.getDocumentElement();
final List<Element> tilesConfig = XmlUtils.findElements("/config/bean",
configElement);
for (final Element bean : tilesConfig) {
final Node importedBean = mvcConfigDocument.importNode(bean, true);
beans.appendChild(importedBean);
}
fileManager.createOrUpdateTextFileIfRequired(mvcConfig,
XmlUtils.nodeToString(mvcConfigDocument), true);
}
public void updateTags(final boolean backup, final LogicalPath webappPath) {
if (backup) {
backupOperations.backup();
}
// Update tags
copyDirectoryContents("tags/form/*.tagx",
pathResolver.getIdentifier(webappPath, "WEB-INF/tags/form"),
true);
copyDirectoryContents("tags/form/fields/*.tagx",
pathResolver.getIdentifier(webappPath,
"WEB-INF/tags/form/fields"), true);
copyDirectoryContents("tags/menu/*.tagx",
pathResolver.getIdentifier(webappPath, "WEB-INF/tags/menu"),
true);
copyDirectoryContents("tags/util/*.tagx",
pathResolver.getIdentifier(webappPath, "WEB-INF/tags/util"),
true);
}
}