/* * gvNIX is an open source tool for rapid application development (RAD). * Copyright (C) 2010 Generalitat Valenciana * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.gvnix.addon.bootstrap; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.logging.Logger; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.gvnix.addon.bootstrap.listener.BootstrapDependencyListener; import org.gvnix.support.WebProjectUtils; import org.osgi.framework.BundleContext; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.process.manager.FileManager; 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.util.DomUtils; import org.springframework.roo.support.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * Implementation of Bootstrap Addon operations * * @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a * href="http://www.dgti.gva.es">General Directorate for Information * Technologies (DGTI)</a> * @since 1.1 */ @Component @Service public class BootstrapOperationsImpl implements BootstrapOperations { // ------------ OSGi component attributes ---------------- private BundleContext context; private static final String VIEWS = "views/"; private FileManager fileManager; private PathResolver pathResolver; private MetadataService metadataService; private ProjectOperations projectOperations; private WebProjectUtils webProjectUtils; /** * Uses to ensure that dependencyListener will be loaded */ @Reference private BootstrapDependencyListener dependencyListener; private static final Logger LOGGER = Logger .getLogger(BootstrapOperationsImpl.class.getName()); protected void activate(ComponentContext cContext) { context = cContext.getBundleContext(); } /** * If JQuery is installed, the command is available */ public boolean isSetupCommandAvailable() { return getProjectOperations().isFeatureInstalledInFocusedModule( "gvnix-jquery") && !getProjectOperations().isFeatureInstalledInFocusedModule( FEATURE_NAME_GVNIX_BOOTSTRAP); } /** * If bootstrap is installed, the command is available */ public boolean isUpdateCommandAvailable() { return getProjectOperations().isFeatureInstalledInFocusedModule( FEATURE_NAME_GVNIX_BOOTSTRAP); } /** {@inheritDoc} */ public void setup() { // Adding Bootstrap libraries addBootstrapScriptsLibraries(); // Adding bootstrap css addBootstrapStyles(); // Replacing old styles replaceOldStyles(); // Adding bootstrap tags addBootstrapTags(); // Adding layouts updateGvNIXLayouts(); // Updating Views and jQuery elements updateViews(); // Adding image resources addImageResources(); // Updating all views to use jQuery BootstrapUtils.updateJSPViewsToUseJQuery(getPathResolver(), getWebappPath(), getProjectOperations(), getFileManager(), getWebProjectUtils()); } /** {@inheritDoc} */ public void updateTags() { // Adding Bootstrap libraries restoreBootstrapScriptsLibraries(); // Adding bootstrap css restoreBootstrapStyles(); // Replacing old styles replaceOldStyles(); // Adding bootstrap tags addBootstrapTags(); // Adding layouts updateGvNIXLayouts(); // Updating Views and jQuery elements updateViews(); // Adding image resources restoreImageResources(); // Updating all views to use jQuery BootstrapUtils.updateJSPViewsToUseJQuery(getPathResolver(), getWebappPath(), getProjectOperations(), getFileManager(), getWebProjectUtils()); } /** * This method adds the bootstrap libraries to the gvNIX project */ public void addBootstrapScriptsLibraries() { List<String> scriptsFolderFiles = new ArrayList<String>(); Collections.addAll(scriptsFolderFiles, "bootstrap.min.js", "offcanvas.js", "README.txt", "assets/html5shiv.js", "assets/respond.min.js"); Iterator<String> scriptsFolderIterator = scriptsFolderFiles.iterator(); while (scriptsFolderIterator.hasNext()) { String fileName = scriptsFolderIterator.next(); final String scriptFile = getPathResolver() .getFocusedIdentifier(Path.SRC_MAIN_WEBAPP, "scripts/bootstrap/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExists(getFileManager(), getClass(), scriptFile, fileName, "scripts/bootstrap/"); } } /** * This method restore the bootstrap libraries to the gvNIX project */ public void restoreBootstrapScriptsLibraries() { List<String> scriptsFolderFiles = new ArrayList<String>(); Collections.addAll(scriptsFolderFiles, "bootstrap.min.js", "offcanvas.js", "README.txt", "assets/html5shiv.js", "assets/respond.min.js"); Iterator<String> scriptsFolderIterator = scriptsFolderFiles.iterator(); while (scriptsFolderIterator.hasNext()) { String fileName = scriptsFolderIterator.next(); final String scriptFile = getPathResolver() .getFocusedIdentifier(Path.SRC_MAIN_WEBAPP, "scripts/bootstrap/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), scriptFile, fileName, "scripts/bootstrap/"); } } /** * This method adds the bootstrap styles to the gvNIX project */ public void addBootstrapStyles() { List<String> stylesFolderFiles = new ArrayList<String>(); Collections.addAll(stylesFolderFiles, "bootstrap/print.css", "bootstrap/bootstrap.min.css", "bootstrap/jquery-ui.bootstrap.css", "bootstrap/offcanvas.css", "bootstrap/images/ui-bg_glass_75_ffffff_1x400.png", "bootstrap/images/ui-icons_222222_256x240.png", "fonts/glyphicons-halflings-regular.eot", "fonts/glyphicons-halflings-regular.svg", "fonts/glyphicons-halflings-regular.ttf", "fonts/glyphicons-halflings-regular.woff", "fonts/README.txt", "images/sort_asc.png", "images/sort_both.png", "images/sort_desc.png"); Iterator<String> stylesFolderIterator = stylesFolderFiles.iterator(); while (stylesFolderIterator.hasNext()) { String fileName = stylesFolderIterator.next(); final String styleFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "styles/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExists(getFileManager(), getClass(), styleFile, fileName, "styles/"); } } /** * This method restores the bootstrap styles to the gvNIX project */ public void restoreBootstrapStyles() { List<String> stylesFolderFiles = new ArrayList<String>(); Collections.addAll(stylesFolderFiles, "bootstrap/print.css", "bootstrap/bootstrap.min.css", "bootstrap/jquery-ui.bootstrap.css", "bootstrap/offcanvas.css", "bootstrap/images/ui-bg_glass_75_ffffff_1x400.png", "bootstrap/images/ui-icons_222222_256x240.png", "fonts/glyphicons-halflings-regular.eot", "fonts/glyphicons-halflings-regular.svg", "fonts/glyphicons-halflings-regular.ttf", "fonts/glyphicons-halflings-regular.woff", "fonts/README.txt", "images/sort_asc.png", "images/sort_both.png", "images/sort_desc.png"); Iterator<String> stylesFolderIterator = stylesFolderFiles.iterator(); while (stylesFolderIterator.hasNext()) { String fileName = stylesFolderIterator.next(); final String styleFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "styles/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), styleFile, fileName, "styles/"); } } /** * This method replaces the old standard.css with a new one adapted to * Bootstrap3 */ public void replaceOldStyles() { final String styleFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "styles/standard.css"); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), styleFile, "standard.css", "styles/"); } /** * This method adds the bootstrap tags to the correct folder */ public void addBootstrapTags() { List<String> tagsFolderFiles = new ArrayList<String>(); Collections.addAll(tagsFolderFiles, "bootstrap/dialog/modal/message-box.tagx", "bootstrap/util/load-styles-bootstrap.tagx", "menu/category.tagx", "menu/menu.tagx", "jquery/util/panel.tagx", "jquery/form/create.tagx", "jquery/form/find.tagx", "jquery/form/show.tagx", "jquery/form/update.tagx", "jquery/form/fields/checkbox.tagx", "jquery/form/fields/datetime.tagx", "jquery/form/fields/display.tagx", "jquery/form/fields/editor.tagx", "jquery/form/fields/input.tagx", "jquery/form/fields/reference.tagx", "jquery/form/fields/select.tagx", "jquery/form/fields/simple.tagx", "jquery/form/fields/textarea.tagx"); // Adding load scripts no datatable addLoadScriptsNoDatatables(); Iterator<String> tagsFolderIterator = tagsFolderFiles.iterator(); while (tagsFolderIterator.hasNext()) { String fileName = tagsFolderIterator.next(); final String tagFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "WEB-INF/tags/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), tagFile, fileName, "tags/"); } } /** * This method copies load-scripts-bootstrap-no-datatables.tagx to the * project */ public void addLoadScriptsNoDatatables() { final String tagFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "WEB-INF/tags/bootstrap/util/load-scripts-bootstrap.tagx"); BootstrapUtils.createFilesInLocationIfNotExists(getFileManager(), getClass(), tagFile, "load-scripts-bootstrap-no-datatables.tagx", "tags/bootstrap/util/"); } /** * This method updates HTML structure in default gvNIX layouts to use * bootstrap */ public void updateGvNIXLayouts() { List<String> layoutsFolderFiles = new ArrayList<String>(); Collections.addAll(layoutsFolderFiles, "default-menu-cols.jspx", "default.jspx"); Iterator<String> layoutsFolderIterator = layoutsFolderFiles.iterator(); while (layoutsFolderIterator.hasNext()) { String fileName = layoutsFolderIterator.next(); final String layoutFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "WEB-INF/layouts/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), layoutFile, fileName, "layouts/"); } } /** * This method updates HTML structure in default gvNIX views to use * bootstrap */ public void updateViews() { List<String> viewsFolderFiles = new ArrayList<String>(); Collections.addAll(viewsFolderFiles, "footer.jspx", "header.jspx", "index.jspx", "uncaughtException.jspx"); Iterator<String> viewsFolderIterator = viewsFolderFiles.iterator(); while (viewsFolderIterator.hasNext()) { String fileName = viewsFolderIterator.next(); final String viewFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "WEB-INF/views/".concat(fileName)); BootstrapUtils.updateFilesInLocationIfExists(getFileManager(), getClass(), viewFile, fileName, VIEWS); } } /** * This method copies images resources to gvNIX application */ public void addImageResources() { List<String> imageFolderFiles = new ArrayList<String>(); Collections.addAll(imageFolderFiles, "logo_gvnix.png", "favicon.ico"); Iterator<String> imageFolderIterator = imageFolderFiles.iterator(); while (imageFolderIterator.hasNext()) { String fileName = imageFolderIterator.next(); final String imageFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "images/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), imageFile, fileName, "images/"); } } /** * This method copies images resources to gvNIX application */ public void restoreImageResources() { List<String> imageFolderFiles = new ArrayList<String>(); Collections.addAll(imageFolderFiles, "logo_gvnix.png", "favicon.ico"); Iterator<String> imageFolderIterator = imageFolderFiles.iterator(); while (imageFolderIterator.hasNext()) { String fileName = imageFolderIterator.next(); final String imageFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "images/".concat(fileName)); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), imageFile, fileName, "images/"); } } /** * This method update security views to use bootstrap */ public void updateSecurityAddonToBootstrap() { final String viewFile = getPathResolver().getFocusedIdentifier( Path.SRC_MAIN_WEBAPP, "WEB-INF/views/login.jspx"); BootstrapUtils.createFilesInLocationIfNotExistsUpdateIfExists( getFileManager(), getClass(), viewFile, "login.jspx", VIEWS); } /** * Check if login.jspx is modified with bootstrap * * @return */ @Override public boolean isLoginModified() { String dirPath = getPathResolver().getIdentifier(getWebappPath(), "WEB-INF/views/login.jspx"); final Document document = XmlUtils.readXml(getFileManager() .getInputStream(dirPath)); final Element config = document.getDocumentElement(); final Element urlElement = DomUtils.findFirstElementByName("div", config); String value = urlElement.getAttribute("class"); return value.contains("alert alert-danger"); } /** * Check if typical security is installed */ @Override public boolean isTypicalSecurityInstalled() { String dirPath = getPathResolver().getIdentifier(getWebappPath(), "WEB-INF/views/changepassword/index.jspx"); return getFileManager().exists(dirPath); } /** * Creates an instance with the {@code src/main/webapp} path in the current * module * * @return */ public LogicalPath getWebappPath() { return getWebProjectUtils().getWebappPath(getProjectOperations()); } // Feature methods ----- /** * Gets the feature name managed by this operations class. * * @return feature name */ @Override public String getName() { return FEATURE_NAME_GVNIX_BOOTSTRAP; } /** * Returns true if bootstrap is installed */ @Override public boolean isInstalledInModule(String moduleName) { String dirPath = getPathResolver().getIdentifier(getWebappPath(), "scripts/bootstrap/bootstrap.min.js"); return getFileManager().exists(dirPath); } public FileManager getFileManager() { if (fileManager == null) { // Get all Services implement FileManager interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(FileManager.class.getName(), null); for (ServiceReference<?> ref : references) { return (FileManager) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load FileManager on BootstrapOperationsImpl."); return null; } } else { return fileManager; } } public PathResolver getPathResolver() { if (pathResolver == null) { // Get all Services implement PathResolver interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(PathResolver.class.getName(), null); for (ServiceReference<?> ref : references) { return (PathResolver) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load PathResolver on BootstrapOperationsImpl."); return null; } } else { return pathResolver; } } public MetadataService getMetadataService() { if (metadataService == null) { // Get all Services implement MetadataService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( MetadataService.class.getName(), null); for (ServiceReference<?> ref : references) { return (MetadataService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load MetadataService on BootstrapOperationsImpl."); return null; } } else { return metadataService; } } public ProjectOperations getProjectOperations() { if (projectOperations == null) { // Get all Services implement ProjectOperations interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( ProjectOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (ProjectOperations) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load ProjectOperations on BootstrapOperationsImpl."); return null; } } else { return projectOperations; } } public WebProjectUtils getWebProjectUtils() { if (webProjectUtils == null) { // Get all Services implement WebProjectUtils interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( WebProjectUtils.class.getName(), null); for (ServiceReference<?> ref : references) { webProjectUtils = (WebProjectUtils) this.context .getService(ref); return webProjectUtils; } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load WebProjectUtils on BootstrapOperationsImpl."); return null; } } else { return webProjectUtils; } } }