/* * Copyright © 2005 - 2018 TIBCO Software Inc. * http://www.jaspersoft.com. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /* tweakWar.js This is run by the build of jasperserver-war in jasperserver-pro It reads in one more more jiconfig files that specify various updates to configuration files in the JasperServer OS webapp. Current files updated: WEB-INF/applicationContext.xml WEB-INF/applicationContext-security.xml WEB-INF/jasperserver-servlet.xml example file: */ importPackage(java.io); // keep comments and whitespace in XML.ignoreComments = false; XML.ignoreWhitespace = false; function writeFile(path, contents) { var fw = new FileWriter(path); fw.write(contents); fw.close(); } function clobberDir(path) { var dir = new File(path); var list = dir.listFiles(); for (i in list) { // gotta love JS syntax... list[i]["delete"](); } dir["delete"](); } // this returns a list of files with the given extension function getFilesByExtension(dir, ext) { var filter = new FileFilter({ accept: function(f) { return f.name.endsWith("." + ext) }}); var files = new File(dir).listFiles(filter); var paths = []; for (var i in files) { paths.push(files[i].path); } return paths; } function saveXML(xml, filename) { writeFile(filename, xml.toXMLString()); } // look up bean, then property, in a spring bean definition file function beanProperty(root, beanName, propName) { var prop = root.beansNS::bean.(@id == beanName).beansNS::property.(@name == propName); // if not found, create it if (prop.length() == 0) { // print("root: " + root.toXMLString()); // print("bean " + beanName + ": " + root.bean.(@id == beanName).toXMLString()); var newChild = ; newChild.setNamespace(beansNS); root.beansNS::bean.(@id == beanName).appendChild(newChild); prop = root.beansNS::bean.(@id == beanName).beansNS::property.(@name == propName); } return prop; } function debug(str) { // print(str); } function printStackTrace(exp) { if (exp == undefined) { try { exp.toString(); } catch (e) { exp = e; } } // note that user could have caught some other // "exception"- may be even a string or number - // and passed the same as argument. Also, check for // rhinoException property before using it if (exp instanceof Error && exp.rhinoException != undefined) { exp.rhinoException.printStackTrace(); } } var beansNS = new Namespace("http://www.springframework.org/schema/beans"); var wsddNS = new Namespace("http://xml.apache.org/axis/wsdd/"); var noNS = new Namespace(""); var webapp = arguments[0]; var configPath = arguments[1]; var savePath; // = 'oldfiles'; // file locations var appConFile = webapp + '/WEB-INF/applicationContext.xml'; var servletFile = webapp + '/WEB-INF/jasperserver-servlet.xml'; var webXmlFile = webapp + '/WEB-INF/web.xml'; var wsDeployFile = webapp + '/WEB-INF/server-config.wsdd'; // var securityFile = webapp + '/WEB-INF/applicationContext-security.xml'; // read in files to xml var appCon = new XML(readFile(appConFile)); var servlet = new XML(readFile(servletFile)); var webXml = new XML(readFile(webXmlFile)); var wsDeploy = new XML(readFile(wsDeployFile)); // var security = new XML(readFile(securityFile)); try { // save before tweaking if there is a savedir // we can diff easier because the formatting will be the same if (savePath) { clobberDir(savePath); var saveDir = new File(savePath); saveDir.mkdir(); var a = savePath + "/" + new File(appConFile).name; var b = savePath + "/" + new File(servletFile).name; // var c = savePath + "/" + new File(securityFile).name; saveXML(appCon, a); saveXML(servlet, b); // saveXML(security, c); } // file or dir? var cfg = new File(configPath); if (cfg.directory) { configFiles = getFilesByExtension(configPath, 'xml'); } else { configFiles = [ configPath ]; } for (i in configFiles) { var configFile = configFiles[i]; print ("processing config file: " + configFile); // read in config to xml var config = new XML(readFile(configFile)); // get list of hbm configs var sessionMapperList = beanProperty(appCon, 'sessionFactory', 'mappingResources').beansNS::list; // get list of hbm configs we want to add and add them var hclist = config.addHibernateConfig; for (var hc in hclist) { var newChild = {hclist[hc].@hbmfile}; newChild.setNamespace(beansNS); sessionMapperList.appendChild(newChild); debug('adding hbm config ' + hclist[hc].@hbmfile); } // get list of client mappings var clientClassMappings = beanProperty(appCon, 'mappingResourceFactory', 'implementationClassMappings').beansNS::map; // get list of mappings we want to add and add them var ccmlist = config.addClientClassMapping; for (var ccm in ccmlist) { var newChild = ; newChild.setNamespace(beansNS); clientClassMappings.appendChild(newChild); debug('adding client class mapping: ' + newChild); } // get list of persistent mappings var persistentClassMappings = beanProperty(appCon, 'persistentMappings', 'implementationClassMappings').beansNS::map; // get list of mappings we want to add and add them var pcmlist = config.addPersistentClassMapping; for (var pcm in pcmlist) { var newChild = ; newChild.setNamespace(beansNS); persistentClassMappings.appendChild(newChild); debug('adding persistent class mapping: ' + newChild); } var handlerMappings = beanProperty(servlet, 'urlHandlerMapping', 'properties').beansNS::props; var methodMappings = beanProperty(servlet, 'paramResolver', 'mappings').beansNS::props; // get JSPs that we want to add var newJSPs = config.addJSP; for (i in newJSPs) { var jsp = newJSPs[i]; debug('adding new jsp: ' + jsp); // construct uri from jsp var uri = '/' + jsp.@jsp + '.html'; var newHandlerMapping = { jsp.@controllerBean } ; newHandlerMapping.setNamespace(beansNS); handlerMappings.appendChild(newHandlerMapping); var newMethodMapping = { jsp.@jsp } ; newMethodMapping.setNamespace(beansNS); methodMappings.appendChild(newMethodMapping); // add role to filterInvocationInterceptor if present /* if (jsp.@role) { var pageRolesDef = security. beansNS::bean.(@id == 'filterInvocationInterceptor'). beansNS::property.(@name == 'objectDefinitionSource').beansNS::value; var pageRoles = pageRolesDef.toString().split('\n'); // add new role before first pattern (contains '=') for (i in pageRoles) { if (pageRoles[i].indexOf('=') > -1) { pageRoles.splice(i, 0, uri.toLowerCase() + '=' + jsp.@roles); break; } } // put roles together again, and put back into XML pageRolesDef.* = pageRoles.join('\n'); } */ } // add filter to filter chain in security /* var newFilters = config.addFilter; for (i in newFilters) { var newFilter = newFilters[i]; debug('adding new filter: ' + newFilter); var filterDef = beanProperty( security, 'filterChainProxy', 'filterInvocationDefinitionSource').beansNS::value; var filters = filterDef.toString().split('\n'); // find filter with matching pattern, and insert new filter before desired location for (i in filters) { if (filters[i].indexOf(newFilter.@pattern + '=') > -1) { var index = filters[i].indexOf(newFilter.@before); if (index > -1) { filters[i] = filters[i].slice(0, index) + newFilter.@filterBean + ',' + filters[i].slice(index); break; } } } // put filters together again, and put back into XML filterDef.* = filters.join('\n'); } */ // add message catalogs to messageSource in appCon var newCats = config.addMessageCatalog; var msgCatList = beanProperty(appCon, 'messageSource', 'basenames').beansNS::list; for (i in newCats) { var newCat = newCats[i]; var newChild = WEB-INF/bundles/{ newCat.@name }; newChild.setNamespace(beansNS); msgCatList.appendChild(newChild); } // add internal catalogs to messageSource in appCon var newIntCats = config.addInternalCatalog; for (i in newIntCats) { var newIntCat = newIntCats[i]; var newChild = WEB-INF/internal/{ newIntCat.@name }; newChild.setNamespace(beansNS); msgCatList.appendChild(newChild); } // generic updates of files (powerful but dangerous!) for each (var ev in config.evalOnFile) { var path = webapp + '/' + ev.@path; var top = new XML(readFile(path)); if (savePath) { var saveFile = savePath + "/" + new File(path).name; saveXML(top, saveFile); } for each (var expr in ev.expr) { try { eval(expr.toString()); } catch (e) { print('error evaluating ' + expr + ' in file ' + ev.@path); print(e); } } saveXML(top, path); } // generic updates of properties for each (var setProp in config.setProperty) { // should map to one of our files (appCon, servlet, security) or else it'll blow up // TODO allow child element as value // TODO generic adding things to lists, props, maps, etc. if (setProp.@file.length() > 0) { eval("var file = " + setProp.@file); var prop = beanProperty(file, setProp.@bean, setProp.@property); prop.@value = setProp.@value; } else if (setProp.@path.length() > 0) { var path = webapp + '/' + setProp.@path; var file = new XML(readFile(path)); var prop = beanProperty(file, setProp.@bean, setProp.@property); prop.@value = setProp.@value; saveXML(file, path); } } // web xml stuff, set default namespace correctly default xml namespace = webXml.namespace(); // add listeners to web.xml, after first listener for each (var addListener in config.noNS::addListener) { var listenerNode = { addListener.@noNS::className } ; if (addListener.@noNS::position == 'last') { webXml.insertChildAfter(webXml.listener[webXml.listener.length() - 1], listenerNode); } else { webXml.insertChildBefore(webXml.listener[0], listenerNode); } } // add filters to web.xml, after last filter for each (var filter in config.noNS::addServletSpringFilter) { var filterNode = {filter.@noNS::beanName} org.springframework.web.filter.DelegatingFilterProxy ; var filterMappingNode = {filter.@noNS::beanName} {filter.@noNS::urlPattern} ; webXml.insertChildAfter(webXml.filter[webXml.filter.length() - 1], filterNode); webXml.insertChildAfter(webXml.filter[webXml.filter.length() - 1], filterMappingNode); } // set web.xml context param // only works if param's already there for each (var setContextParam in config.noNS::setContextParam) { for each(var p in webXml['context-param']) { if (p['param-name'] == setContextParam.@noNS::name) { p['param-value'] = setContextParam.@noNS::value; break; } } } for each (var setServletClass in config.noNS::setServletClass) { for each(var p in webXml['servlet']) { if (p['servlet-name'] == setServletClass.@noNS::name) { p['servlet-class'] = setServletClass.@noNS::className; break; } } } for each (var addServlet in config.noNS::addServlet) { webXml.appendChild( {addServlet.@noNS::name} {addServlet.@noNS::className} ); webXml.appendChild( {addServlet.@noNS::name} {addServlet.@noNS::urlPattern} ); } //Web Services default xml namespace = wsDeploy.namespace(); for each (var addService in config.noNS::addService) { for each (var service in addService.wsddNS::service) { wsDeploy.appendChild(service); } } // reset default xml namespace = ""; } // write file saveXML(appCon, appConFile); saveXML(servlet, servletFile); saveXML(webXml, webXmlFile); saveXML(wsDeploy, wsDeployFile); // saveXML(security, securityFile); } catch (e) { printStackTrace(e); }