/* * 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.web.mvc.addon.jquery; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.gvnix.addon.web.mvc.addon.MvcOperations; import org.gvnix.addon.web.mvc.annotations.jquery.GvNIXWebJQuery; import org.gvnix.support.OperationUtils; import org.gvnix.support.WebProjectUtils; import org.osgi.framework.InvalidSyntaxException; import org.osgi.framework.ServiceReference; import org.osgi.service.component.ComponentContext; import org.springframework.roo.addon.web.mvc.controller.addon.details.FinderMetadataDetails; import org.springframework.roo.addon.web.mvc.controller.addon.details.WebMetadataService; import org.springframework.roo.addon.web.mvc.controller.addon.finder.WebFinderMetadata; import org.springframework.roo.addon.web.mvc.controller.addon.scaffold.WebScaffoldAnnotationValues; import org.springframework.roo.addon.web.mvc.controller.annotations.scaffold.RooWebScaffold; 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.MemberFindingUtils; 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.classpath.scanner.MemberDetails; import org.springframework.roo.model.JavaType; import org.springframework.roo.process.manager.MutableFile; import org.springframework.roo.project.FeatureNames; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.PathResolver; import org.springframework.roo.project.ProjectOperations; import org.springframework.roo.project.maven.Pom; import org.springframework.roo.support.logging.HandlerUtils; import org.springframework.roo.support.util.XmlUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * Implementation of operations this add-on offers. * * @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 JQueryOperationsImpl extends AbstractOperations implements JQueryOperations { protected final static Logger LOGGER = HandlerUtils .getLogger(JQueryOperationsImpl.class); private static final String PATH_IS_NOT_SPECIFIED = "Path is not specified in the @RooWebScaffold annotation for '"; private static final String JQUERY_FORM_PATH = "urn:jsptagdir:/WEB-INF/tags/jquery/form"; private static final String FORM_FIELDS_PATH = "urn:jsptagdir:/WEB-INF/tags/form/fields"; private static final String XMLNS_UTIL = "xmlns:util"; private static final String XMLNS_PAGE = "xmlns:page"; private static final String XMLNS_TABLE = "xmlns:table"; private static final String XMLNS_FORM = "xmlns:form"; private static final String XMLNS_FIELD = "xmlns:field"; private ComponentContext cContext; protected void activate(final ComponentContext componentContext) { cContext = componentContext; context = cContext.getBundleContext(); } private static final JavaType SCAFFOLD_ANNOTATION = new JavaType( RooWebScaffold.class.getName()); private static final JavaType JQUERY_ANNOTATION = new JavaType( GvNIXWebJQuery.class.getName()); private ProjectOperations projectOperations; private MvcOperations mvcOperations; private TypeLocationService typeLocationService; private TypeManagementService typeManagementService; private WebMetadataService webMetadataService; private WebProjectUtils webProjectUtils; private OperationUtils operationUtils; /** * {@inheritDoc} * <p/> * Setup is available if Spring MVC and gvNIX MVC jQuery files have not been * installed yet. * <p/> * Note gvNIX MVC dependencies aren't checked because {@link #setup()} will * install them if they are missing */ public boolean isSetupAvailable() { return getProjectOperations().isFeatureInstalledInFocusedModule( FeatureNames.MVC) && !getProjectOperations().isFeatureInstalledInFocusedModule( FEATURE_NAME_GVNIX_JQUERY); } public boolean isAddAvailable() { return getProjectOperations().isFeatureInstalledInFocusedModule( FEATURE_NAME_GVNIX_JQUERY); } public boolean isUpdateTagsAvailable() { return isAddAvailable(); } public void annotateAll() { // Locate all controllers and annotate it for (JavaType type : getTypeLocationService().findTypesWithAnnotation( SCAFFOLD_ANNOTATION)) { annotateController(type); } } public void annotateController(JavaType javaType) { Validate.notNull(javaType, "Controller required"); ClassOrInterfaceTypeDetails existing = getControllerDetails(javaType); // Only for @RooWebScaffold annotated controllers final AnnotationMetadata controllerAnnotation = MemberFindingUtils .getAnnotationOfType(existing.getAnnotations(), SCAFFOLD_ANNOTATION); Validate.isTrue(controllerAnnotation != null, "Operation for @RooWebScaffold annotated controllers only."); final boolean isJQueryAnnotated = MemberFindingUtils .getAnnotationOfType(existing.getAnnotations(), JQUERY_ANNOTATION) != null; // If annotation already exists on the target type do nothing if (isJQueryAnnotated) { return; } ClassOrInterfaceTypeDetailsBuilder detailsBuilder = new ClassOrInterfaceTypeDetailsBuilder( existing); AnnotationMetadataBuilder annotationBuilder = new AnnotationMetadataBuilder( JQUERY_ANNOTATION); // Add annotation to target type detailsBuilder.addAnnotation(annotationBuilder.build()); // Save changes to disk getTypeManagementService().createOrUpdateTypeOnDisk( detailsBuilder.build()); } /** * Updates all JSP pages of target controller to use JQuery * * @param controller * @param controllerAnnotation */ public void updateCommonJsp() { // List of pages to update List<String> pageList = new ArrayList<String>(); Collections.addAll(pageList, "dataAccessFailure", "resourceNotFound", "uncaughtException", "index", "login"); // 3rd party add-ons could customize default Roo tags as gvNIX does, // to avoid to overwrite them with jQuery namespaces we will update // default Roo namespaces only Map<String, String> rooUriMap = new HashMap<String, String>(); rooUriMap.put(XMLNS_FIELD, FORM_FIELDS_PATH); rooUriMap.put(XMLNS_FORM, "urn:jsptagdir:/WEB-INF/tags/form"); rooUriMap.put(XMLNS_TABLE, FORM_FIELDS_PATH); rooUriMap.put(XMLNS_PAGE, "urn:jsptagdir:/WEB-INF/tags/form"); rooUriMap.put(XMLNS_UTIL, "urn:jsptagdir:/WEB-INF/tags/util"); // new jQuery namespaces Map<String, String> uriMap = new HashMap<String, String>(); uriMap.put(XMLNS_FIELD, "urn:jsptagdir:/WEB-INF/tags/jquery/form/fields"); uriMap.put(XMLNS_FORM, JQUERY_FORM_PATH); uriMap.put(XMLNS_TABLE, "urn:jsptagdir:/WEB-INF/tags/jquery/form/fields"); uriMap.put(XMLNS_PAGE, JQUERY_FORM_PATH); uriMap.put(XMLNS_UTIL, "urn:jsptagdir:/WEB-INF/tags/jquery/util"); // do the update for (String jspxName : pageList) { getWebProjectUtils().updateTagxUriInJspx( "WEB-INF/views/".concat(jspxName).concat(".jspx"), rooUriMap, uriMap, getProjectOperations(), fileManager); } } /** * Updates all JSP pages of target controller to use JQuery * * @param controller * @param controllerAnnotation */ public void updateCrudJsp(JavaType controller, JQueryMetadata jqueryMetadata) { Validate.notNull(jqueryMetadata, "JQuery metadata required"); String controllerPath = jqueryMetadata.getWebScaffoldAnnotationValues() .getPath(); Validate.notBlank(controllerPath, PATH_IS_NOT_SPECIFIED.concat(controller.getSimpleTypeName()) .concat("'")); Validate.isTrue(controllerPath != null && !controllerPath.isEmpty(), PATH_IS_NOT_SPECIFIED.concat(controller.getSimpleTypeName()) .concat("'")); if (controllerPath != null && !controllerPath.startsWith("/")) { controllerPath = "/".concat(controllerPath); } // List of pages to update List<String> pageList = new ArrayList<String>(); Collections.addAll(pageList, "create", "list", "show", "update"); // 3rd party add-ons could customize default Roo tags as gvNIX does, // to avoid to overwrite them with jQuery namespaces we will update // default Roo namespaces only Map<String, String> rooUriMap = new HashMap<String, String>(); rooUriMap.put(XMLNS_FIELD, FORM_FIELDS_PATH); rooUriMap.put(XMLNS_FORM, "urn:jsptagdir:/WEB-INF/tags/form"); rooUriMap.put(XMLNS_TABLE, FORM_FIELDS_PATH); rooUriMap.put(XMLNS_PAGE, "urn:jsptagdir:/WEB-INF/tags/form"); rooUriMap.put(XMLNS_UTIL, "urn:jsptagdir:/WEB-INF/tags/util"); // new jQuery namespaces Map<String, String> uriMap = new HashMap<String, String>(); uriMap.put(XMLNS_FIELD, "urn:jsptagdir:/WEB-INF/tags/jquery/form/fields"); uriMap.put(XMLNS_FORM, JQUERY_FORM_PATH); uriMap.put(XMLNS_TABLE, "urn:jsptagdir:/WEB-INF/tags/jquery/form/fields"); uriMap.put(XMLNS_PAGE, JQUERY_FORM_PATH); uriMap.put(XMLNS_UTIL, "urn:jsptagdir:/WEB-INF/tags/jquery/util"); // do the update for (String jspxName : pageList) { getWebProjectUtils().updateTagxUriInJspx(controllerPath, jspxName, rooUriMap, uriMap, getProjectOperations(), fileManager); } } /** * Updates all JSP pages of target controller to use JQuery * * @param controller * @param controllerAnnotation */ public void updateFindJsp(JavaType controller, WebFinderMetadata finderMetadata) { Validate.notNull(finderMetadata, "Finder metadata required"); WebScaffoldAnnotationValues annotationValues = finderMetadata .getAnnotationValues(); // Get view path for success file access in "WEB-INF/views/" String controllerPath = annotationValues.getPath(); Validate.notBlank(controllerPath, PATH_IS_NOT_SPECIFIED.concat(controller.getSimpleTypeName()) .concat("'")); Validate.isTrue(controllerPath != null && !controllerPath.isEmpty(), PATH_IS_NOT_SPECIFIED.concat(controller.getSimpleTypeName()) .concat("'")); // Get Java type details JavaType formBackingType = annotationValues.getFormBackingObject(); MemberDetails memberDetails = getWebMetadataService().getMemberDetails( formBackingType); // This controller is annotated with @RooWebFinder final Set<FinderMetadataDetails> finderMethodsDetails = getWebMetadataService() .getDynamicFinderMethodsAndFields(formBackingType, memberDetails, finderMetadata.getId()); if (finderMethodsDetails == null) { // No finders found, do nothing return; } // 3rd party add-ons could customize default Roo tags as gvNIX does, // to avoid to overwrite them with jQuery namespaces we will update // default Roo namespaces only Map<String, String> rooUriMap = new HashMap<String, String>(); rooUriMap.put(XMLNS_FIELD, FORM_FIELDS_PATH); rooUriMap.put(XMLNS_FORM, "urn:jsptagdir:/WEB-INF/tags/form"); rooUriMap.put(XMLNS_TABLE, FORM_FIELDS_PATH); rooUriMap.put(XMLNS_PAGE, "urn:jsptagdir:/WEB-INF/tags/form"); rooUriMap.put(XMLNS_UTIL, "urn:jsptagdir:/WEB-INF/tags/util"); // new jQuery namespaces Map<String, String> uriMap = new HashMap<String, String>(); uriMap.put(XMLNS_FIELD, "urn:jsptagdir:/WEB-INF/tags/jquery/form/fields"); uriMap.put(XMLNS_FORM, JQUERY_FORM_PATH); uriMap.put(XMLNS_TABLE, "urn:jsptagdir:/WEB-INF/tags/jquery/form/fields"); uriMap.put(XMLNS_PAGE, JQUERY_FORM_PATH); uriMap.put(XMLNS_UTIL, "urn:jsptagdir:/WEB-INF/tags/jquery/util"); // do the update for (final FinderMetadataDetails finderDetails : finderMethodsDetails) { final String finderName = finderDetails.getFinderMethodMetadata() .getMethodName().getSymbolName(); getWebProjectUtils().updateTagxUriInJspx( "WEB-INF/views/".concat(controllerPath).concat("/") .concat(finderName).concat(".jspx"), rooUriMap, uriMap, getProjectOperations(), fileManager); } } /** * @param controller * @return */ protected ClassOrInterfaceTypeDetails getControllerDetails( JavaType controller) { ClassOrInterfaceTypeDetails existing = getTypeLocationService() .getTypeDetails(controller); Validate.notNull(existing, "Can't get Type details"); return existing; } /** * {@inheritDoc} * <p/> * Copy jQuery JS, CSS, images, customized TAGx, et al files to current * project. * <p/> * Note this method copies needed artifacts only, to transform current views * to jQuery views you must annotate manually the Controller with * {@link GvNIXWebJQuery} or use {@code web mvc jquery add} and * {@code web mvc jquery all} commands to annotate the Controller. */ public void setup() { // If gvNIX MVC dependencies are not installed, install them if (!getProjectOperations().isFeatureInstalledInFocusedModule( MvcOperations.FEATURE_NAME_GVNIX_MVC)) { getMvcOperations().setup(); } // Install tags modified for jQuery support updateTags(); // Install common JSP modified for jQuery support updateCommonJsp(); // Configure load-scripts.tagx updateLoadScriptsTag(); } public void updateLoadScriptsTag() { // Modify Roo load-scripts.tagx PathResolver pathResolver = getProjectOperations().getPathResolver(); String docTagxPath = pathResolver.getIdentifier(getWebappPath(), "WEB-INF/tags/util/load-scripts.tagx"); Validate.isTrue(fileManager.exists(docTagxPath), "load-script.tagx not found: ".concat(docTagxPath)); MutableFile docTagxMutableFile = null; Document docTagx; try { docTagxMutableFile = fileManager.updateFile(docTagxPath); docTagx = XmlUtils.getDocumentBuilder().parse( docTagxMutableFile.getInputStream()); } catch (Exception e) { throw new IllegalStateException(e); } Element root = docTagx.getDocumentElement(); boolean modified = false; // Add jquery-ui.css modified = getWebProjectUtils().addCssToTag(docTagx, root, "jquery_ui_css_url", "/resources/styles/jquery/jquery-ui.css") || modified; // Add jquery.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_js_url", "/resources/scripts/jquery/jquery-min.js") || modified; // Add jquery-ui.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_ui_js_url", "/resources/scripts/jquery/jquery-ui.min.js") || modified; // Add jquery.base64.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_b64_js_url", "/resources/scripts/jquery/jquery.base64.js") || modified; // Add tinymce.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "tinymce_js_url", "/resources/scripts/jquery/tinymce.min.js") || modified; // Add jQuery tinymce.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_tinymce_js_url", "/resources/scripts/jquery/jquery.tinymce.min.js") || modified; // Add jQuery validate.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_validate_js_url", "/resources/scripts/jquery/jquery.validate-min.js") || modified; // Add jQuery application JS init modified = getWebProjectUtils().addJSToTag(docTagx, root, "app_js_url", "/resources/scripts/jquery/application.js") || modified; // Add jQuery cookie.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_cookie_js_url", "/resources/scripts/jquery/jquery.cookie.js") || modified; // Add i18n customization var modified = getWebProjectUtils().addLocaleVarToTag(docTagx, root, "jqueryLocale") || modified; // Add jQuery UI datepicker i18n modified = getWebProjectUtils() .addJSToTag(docTagx, root, "jquery_ui_i18n_js_url", "/resources/scripts/jquery/i18n/jquery.ui.datepicker-${jqueryLocale}.js") || modified; // Add jQuery validate i18n modified = getWebProjectUtils() .addJSToTag(docTagx, root, "jquery_validate_i18n_js_url", "/resources/scripts/jquery/i18n/jquery.validate-${jqueryLocale}.js") || modified; // Add jQuery hastable.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "hashtable_js_url", "/resources/scripts/jquery/hashtable.js") || modified; // Add jQuery numberformatter.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_numberformatter_js_url", "/resources/scripts/jquery/jquery.numberformatter.min.js") || modified; // Add jQuery.print.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_print_js_url", "/resources/scripts/jquery/jquery.print.js") || modified; // Add jquery.dialogextend.min.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "moment_js_url", "/resources/scripts/jquery/moment.min.js") || modified; // Add moment.min.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_dialog_extend_js_url", "/resources/scripts/jquery/jquery.dialogextend.min.js") || modified; // Add jquery-datetimepicker.css modified = getWebProjectUtils().addCssToTag(docTagx, root, "jquery_datetimepicker_css_url", "/resources/styles/jquery/jquery.datetimepicker.css") || modified; // Add jquery-datetimepicker.min.js modified = getWebProjectUtils().addJSToTag(docTagx, root, "jquery_datetimepicker_js_url", "/resources/scripts/jquery/jquery.datetimepicker.full.min.js") || modified; modified = addMomentAndDatepickerConfig(docTagx, root, "moment_js_locale_url", "/resources/scripts/jquery/i18n/moment-${jqueryLocale}.js"); if (modified) { XmlUtils.writeXml(docTagxMutableFile.getOutputStream(), docTagx); } } // Feature methods ----- /** * Gets the feature name managed by this operations class. * * @return feature name */ public String getName() { return FEATURE_NAME_GVNIX_JQUERY; } /** * Returns true if gvNIX Web MVC dependency and gvNIX MVC jQuery files are * installed in current project. * * @param moduleName feature name to check in current project * @return true if given feature name is installed, otherwise returns false */ public boolean isInstalledInModule(final String moduleName) { final Pom pom = getProjectOperations().getPomFromModuleName(moduleName); if (pom == null) { return false; } return getProjectOperations().isFeatureInstalledInFocusedModule( MvcOperations.FEATURE_NAME_GVNIX_MVC) && hasJQueryTags(); } // Helper methods ----- /** * Creates an instance with the {@code src/main/webapp} path in the current * module * * @return */ private LogicalPath getWebappPath() { return getWebProjectUtils().getWebappPath(getProjectOperations()); } /** * Check if {@code WEB-INF/tags/jquery} and * {@code scripts/jquery/jquery-min.js} exist * * @return */ private boolean hasJQueryTags() { PathResolver pathResolver = getProjectOperations().getPathResolver(); String dirPath = pathResolver.getIdentifier(getWebappPath(), "WEB-INF/tags/jquery"); String jsPath = pathResolver.getIdentifier(getWebappPath(), "scripts/jquery/jquery-min.js"); return fileManager.exists(dirPath) && fileManager.exists(jsPath); } @Override public void updateTags() { PathResolver pathResolver = getProjectOperations().getPathResolver(); LogicalPath webappPath = getWebappPath(); // Copy Javascript files and related resources copyDirectoryContents("scripts/jquery/*.js", pathResolver.getIdentifier(webappPath, "/scripts/jquery"), true); copyDirectoryContents("scripts/jquery/i18n/*.js", pathResolver.getIdentifier(webappPath, "/scripts/jquery/i18n"), true); copyDirectoryContents("scripts/jquery/themes/modern/*.js", pathResolver.getIdentifier(webappPath, "/scripts/jquery/themes/modern"), true); copyDirectoryContents("scripts/jquery/skins/lightgray/*.css", pathResolver.getIdentifier(webappPath, "/scripts/jquery/skins/lightgray"), true); copyDirectoryContents("scripts/jquery/README.txt", pathResolver.getIdentifier(webappPath, "/scripts/jquery"), true); getOperationUtils().updateDirectoryContents( "scripts/jquery/skins/lightgray/fonts/*.*", pathResolver.getIdentifier(webappPath, "/scripts/jquery/skins/lightgray/fonts"), fileManager, cContext, getClass()); getOperationUtils().updateDirectoryContents( "scripts/jquery/skins/lightgray/img/*.*", pathResolver.getIdentifier(webappPath, "/scripts/jquery/skins/lightgray/img"), fileManager, cContext, getClass()); // Copy CSS files and related resources copyDirectoryContents("styles/jquery/*.css", pathResolver.getIdentifier(webappPath, "/styles/jquery"), true); getOperationUtils() .updateDirectoryContents( "styles/jquery/images/*.*", pathResolver.getIdentifier(webappPath, "/styles/jquery/images"), fileManager, cContext, getClass()); // Copy Tagx files copyDirectoryContents("tags/jquery/form/*.tagx", pathResolver.getIdentifier(webappPath, "/WEB-INF/tags/jquery/form"), true); copyDirectoryContents("tags/jquery/form/fields/*.tagx", pathResolver.getIdentifier(webappPath, "/WEB-INF/tags/jquery/form/fields"), true); copyDirectoryContents("tags/jquery/util/*.tagx", pathResolver.getIdentifier(webappPath, "/WEB-INF/tags/jquery/util"), true); } 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 JQueryOperationsImpl."); return null; } } else { return projectOperations; } } public MvcOperations getMvcOperations() { if (mvcOperations == null) { // Get all Services implement MvcOperations interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences(MvcOperations.class.getName(), null); for (ServiceReference<?> ref : references) { return (MvcOperations) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load MvcOperations on JQueryOperationsImpl."); return null; } } else { return mvcOperations; } } public TypeLocationService getTypeLocationService() { if (typeLocationService == null) { // Get all Services implement TypeLocationService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( TypeLocationService.class.getName(), null); for (ServiceReference<?> ref : references) { return (TypeLocationService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load TypeLocationService on JQueryOperationsImpl."); return null; } } else { return typeLocationService; } } public TypeManagementService getTypeManagementService() { if (typeManagementService == null) { // Get all Services implement TypeManagementService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( TypeManagementService.class.getName(), null); for (ServiceReference<?> ref : references) { return (TypeManagementService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load TypeManagementService on JQueryOperationsImpl."); return null; } } else { return typeManagementService; } } public WebMetadataService getWebMetadataService() { if (webMetadataService == null) { // Get all Services implement WebMetadataService interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( WebMetadataService.class.getName(), null); for (ServiceReference<?> ref : references) { return (WebMetadataService) this.context.getService(ref); } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load WebMetadataService on JQueryOperationsImpl."); return null; } } else { return webMetadataService; } } 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 JQueryOperationsImpl."); return null; } } else { return webProjectUtils; } } public OperationUtils getOperationUtils() { if (operationUtils == null) { // Get all Services implement OperationUtils interface try { ServiceReference<?>[] references = this.context .getAllServiceReferences( OperationUtils.class.getName(), null); for (ServiceReference<?> ref : references) { operationUtils = (OperationUtils) this.context .getService(ref); return operationUtils; } return null; } catch (InvalidSyntaxException e) { LOGGER.warning("Cannot load OperationUtils on JQueryOperationsImpl."); return null; } } else { return operationUtils; } } private boolean addMomentAndDatepickerConfig(Document docTagx, Element root, String varName, String location) { boolean modified = false; // add url resolution modified = getWebProjectUtils().addUrlToTag(docTagx, root, varName, location); // Add script Element scriptElement = XmlUtils.findFirstElement( String.format("script[@src='${%s}']", varName), root); if (scriptElement == null) { scriptElement = docTagx.createElement("script"); scriptElement.setAttribute("src", "${".concat(varName).concat("}")); scriptElement.setAttribute("type", "text/javascript"); scriptElement.appendChild(docTagx .createComment("required for FF3 and Opera")); root.appendChild(scriptElement); modified = true; // Add configuration script Element scriptConfigElement = docTagx.createElement("script"); scriptConfigElement.setAttribute("type", "text/javascript"); StringBuilder strb = new StringBuilder(); strb.append("// set momentjs and jQuery datetimepicker locale\n"); strb.append("moment.locale('${jqueryLocale}');\n"); strb.append("jQuery.datetimepicker.setLocale('${jqueryLocale}');\n"); strb.append("\n"); strb.append("// Define parse/format date using moment library\n"); strb.append("Date.parseDate = function( input, format ){\n"); strb.append(" return moment(input,format).toDate();\n"); strb.append("};\n"); strb.append("Date.prototype.dateFormat = function( format ){\n"); strb.append(" return moment(this).format(format);\n"); strb.append("};\n"); scriptConfigElement.appendChild(docTagx.createTextNode(strb .toString())); root.appendChild(scriptConfigElement); } return modified; } }