001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.configuration; 029 030import org.opencms.file.CmsObject; 031import org.opencms.i18n.CmsEncoder; 032import org.opencms.main.CmsLog; 033import org.opencms.util.CmsFileUtil; 034import org.opencms.util.CmsStringUtil; 035import org.opencms.xml.CmsXmlEntityResolver; 036import org.opencms.xml.CmsXmlErrorHandler; 037 038import java.io.ByteArrayInputStream; 039import java.io.ByteArrayOutputStream; 040import java.io.File; 041import java.io.FileOutputStream; 042import java.io.IOException; 043import java.io.OutputStream; 044import java.io.PrintStream; 045import java.net.InetAddress; 046import java.net.URL; 047import java.text.SimpleDateFormat; 048import java.util.ArrayList; 049import java.util.Date; 050import java.util.Iterator; 051import java.util.List; 052 053import javax.xml.parsers.ParserConfigurationException; 054import javax.xml.parsers.SAXParserFactory; 055import javax.xml.transform.OutputKeys; 056import javax.xml.transform.Result; 057import javax.xml.transform.Source; 058import javax.xml.transform.Transformer; 059import javax.xml.transform.TransformerException; 060import javax.xml.transform.TransformerFactory; 061import javax.xml.transform.sax.SAXSource; 062import javax.xml.transform.stream.StreamResult; 063import javax.xml.transform.stream.StreamSource; 064 065import org.apache.commons.digester3.Digester; 066import org.apache.commons.logging.Log; 067 068import org.dom4j.Document; 069import org.dom4j.DocumentHelper; 070import org.dom4j.Element; 071import org.dom4j.dom.DOMDocumentType; 072import org.dom4j.io.OutputFormat; 073import org.dom4j.io.XMLWriter; 074import org.xml.sax.InputSource; 075import org.xml.sax.SAXException; 076import org.xml.sax.XMLReader; 077 078/** 079 * Configuration manager for digesting the OpenCms XML configuration.<p> 080 * 081 * Reads the individual configuration class nodes first and creaes new 082 * instances of the "base" configuration classes.<p> 083 * 084 * @since 6.0.0 085 */ 086public class CmsConfigurationManager implements I_CmsXmlConfiguration { 087 088 /** The location of the OpenCms configuration DTD if the default prefix is the system ID. */ 089 public static final String DEFAULT_DTD_LOCATION = "org/opencms/configuration/"; 090 091 /** Location of the optional XSLT file used to transform the configuration. */ 092 public static final String DEFAULT_XSLT_FILENAME = "opencms-configuration.xslt"; 093 094 /** The default prefix for the OpenCms configuration DTD. */ 095 public static final String DEFAULT_DTD_PREFIX = "http://www.opencms.org/dtd/6.0/"; 096 097 /** The name of the default XML file for this configuration. */ 098 public static final String DEFAULT_XML_FILE_NAME = "opencms.xml"; 099 100 /** The name of the DTD file for this configuration. */ 101 public static final String DTD_FILE_NAME = "opencms-configuration.dtd"; 102 103 /** The "opencms" root node of the XML configuration. */ 104 public static final String N_ROOT = "opencms"; 105 106 /** Postfix for original configuration files. */ 107 public static final String POSTFIX_ORI = ".ori"; 108 109 /** The config node. */ 110 protected static final String N_CONFIG = "config"; 111 112 /** The configurations node. */ 113 protected static final String N_CONFIGURATION = "configuration"; 114 115 /** Date format for the backup file time prefix. */ 116 private static final SimpleDateFormat BACKUP_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_"); 117 118 /** The log object for this class. */ 119 private static final Log LOG = CmsLog.getLog(CmsConfigurationManager.class); 120 121 /** The number of days to keep old backups for. */ 122 private static final long MAX_BACKUP_DAYS = 15; 123 124 /** The folder where to store the backup files of the configuration. */ 125 private File m_backupFolder; 126 127 /** The base folder where the configuration files are located. */ 128 private File m_baseFolder; 129 130 /** The initialized configuration classes. */ 131 private List<I_CmsXmlConfiguration> m_configurations; 132 133 /** The digester for reading the XML configuration. */ 134 private Digester m_digester; 135 136 /** The configuration based on <code>opencms.properties</code>. */ 137 private CmsParameterConfiguration m_propertyConfiguration; 138 139 /** The admin CmsObject. */ 140 private CmsObject m_adminCms; 141 142 /** 143 * Creates a new OpenCms configuration manager.<p> 144 * 145 * @param baseFolder base folder where XML configurations to load are located 146 */ 147 public CmsConfigurationManager(String baseFolder) { 148 149 m_baseFolder = new File(baseFolder); 150 if (!m_baseFolder.exists()) { 151 if (LOG.isErrorEnabled()) { 152 LOG.error( 153 Messages.get().getBundle().key( 154 Messages.LOG_INVALID_CONFIG_BASE_FOLDER_1, 155 m_baseFolder.getAbsolutePath())); 156 } 157 } 158 m_backupFolder = new File(m_baseFolder.getAbsolutePath() + File.separatorChar + "backup"); 159 if (!m_backupFolder.exists()) { 160 if (LOG.isDebugEnabled()) { 161 LOG.debug( 162 Messages.get().getBundle().key( 163 Messages.LOG_CREATE_CONFIG_BKP_FOLDER_1, 164 m_backupFolder.getAbsolutePath())); 165 } 166 m_backupFolder.mkdirs(); 167 } 168 if (LOG.isDebugEnabled()) { 169 LOG.debug( 170 Messages.get().getBundle().key(Messages.LOG_CONFIG_BASE_FOLDER_1, m_baseFolder.getAbsolutePath())); 171 LOG.debug( 172 Messages.get().getBundle().key(Messages.LOG_CONFIG_BKP_FOLDER_1, m_backupFolder.getAbsolutePath())); 173 } 174 cacheDtdSystemId(this); 175 m_configurations = new ArrayList<I_CmsXmlConfiguration>(); 176 } 177 178 /** 179 * Adds a configuration object to the configuration manager.<p> 180 * 181 * @param configuration the configuration to add 182 */ 183 public void addConfiguration(I_CmsXmlConfiguration configuration) { 184 185 if (LOG.isDebugEnabled()) { 186 LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_CONFIG_1, configuration)); 187 } 188 m_configurations.add(configuration); 189 cacheDtdSystemId(configuration); 190 } 191 192 /** 193 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String) 194 */ 195 public void addConfigurationParameter(String paramName, String paramValue) { 196 197 // noop, this configuration has no additional parameters 198 } 199 200 /** 201 * @see org.opencms.configuration.I_CmsXmlConfiguration#addXmlDigesterRules(org.apache.commons.digester3.Digester) 202 */ 203 public void addXmlDigesterRules(Digester digester) { 204 205 // add rule for <configuration> node 206 digester.addObjectCreate( 207 "*/" + N_CONFIGURATION + "/" + N_CONFIG, 208 CmsConfigurationException.class.getName(), 209 I_CmsXmlConfiguration.A_CLASS); 210 digester.addSetNext("*/" + N_CONFIGURATION + "/" + N_CONFIG, "addConfiguration"); 211 } 212 213 /** 214 * @see org.opencms.configuration.I_CmsXmlConfiguration#generateXml(org.dom4j.Element) 215 */ 216 public Element generateXml(Element parent) { 217 218 // add the <configuration> node 219 Element configurationElement = parent.addElement(N_CONFIGURATION); 220 for (int i = 0; i < m_configurations.size(); i++) { 221 // append the individual configuration 222 I_CmsXmlConfiguration configuration = m_configurations.get(i); 223 configurationElement.addElement(N_CONFIG).addAttribute( 224 I_CmsXmlConfiguration.A_CLASS, 225 configuration.getClass().getName()); 226 } 227 return parent; 228 } 229 230 /** 231 * Creates the XML document build from the provided configuration.<p> 232 * 233 * @param configuration the configuration to build the XML for 234 * @return the XML document build from the provided configuration 235 */ 236 public Document generateXml(I_CmsXmlConfiguration configuration) { 237 238 // create a new document 239 Document result = DocumentHelper.createDocument(); 240 241 // set the document type 242 DOMDocumentType docType = new DOMDocumentType(); 243 docType.setElementName(N_ROOT); 244 docType.setSystemID(configuration.getDtdUrlPrefix() + configuration.getDtdFilename()); 245 result.setDocType(docType); 246 247 Element root = result.addElement(N_ROOT); 248 // start the XML generation 249 configuration.generateXml(root); 250 251 // return the resulting document 252 return result; 253 } 254 255 /** 256 * Returns the backup folder.<p> 257 * 258 * @return the backup folder 259 */ 260 public File getBackupFolder() { 261 262 return m_backupFolder; 263 } 264 265 /** 266 * Returns the properties read from <code>opencms.properties</code>.<p> 267 * 268 * @see #setConfiguration(CmsParameterConfiguration) 269 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration() 270 */ 271 public CmsParameterConfiguration getConfiguration() { 272 273 return m_propertyConfiguration; 274 } 275 276 /** 277 * Returns a specific configuration from the list of initialized configurations.<p> 278 * 279 * @param clazz the configuration class that should be returned 280 * @return the initialized configuration class instance, or <code>null</code> if this is not found 281 */ 282 public I_CmsXmlConfiguration getConfiguration(Class<?> clazz) { 283 284 for (int i = 0; i < m_configurations.size(); i++) { 285 I_CmsXmlConfiguration configuration = m_configurations.get(i); 286 if (clazz.equals(configuration.getClass())) { 287 return configuration; 288 } 289 } 290 return null; 291 } 292 293 /** 294 * Returns the list of all initialized configurations.<p> 295 * 296 * @return the list of all initialized configurations 297 */ 298 public List<I_CmsXmlConfiguration> getConfigurations() { 299 300 return m_configurations; 301 } 302 303 /** 304 * @see org.opencms.configuration.I_CmsXmlConfiguration#getDtdFilename() 305 */ 306 public String getDtdFilename() { 307 308 return DTD_FILE_NAME; 309 } 310 311 /** 312 * @see org.opencms.configuration.I_CmsXmlConfiguration#getDtdSystemLocation() 313 */ 314 public String getDtdSystemLocation() { 315 316 return DEFAULT_DTD_LOCATION; 317 } 318 319 /** 320 * @see org.opencms.configuration.I_CmsXmlConfiguration#getDtdUrlPrefix() 321 */ 322 public String getDtdUrlPrefix() { 323 324 return DEFAULT_DTD_PREFIX; 325 } 326 327 /** 328 * @see org.opencms.configuration.I_CmsXmlConfiguration#getXmlFileName() 329 */ 330 public String getXmlFileName() { 331 332 return DEFAULT_XML_FILE_NAME; 333 } 334 335 /** 336 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 337 */ 338 public void initConfiguration() { 339 340 // does not need to be initialized 341 if (LOG.isDebugEnabled()) { 342 LOG.debug(Messages.get().getBundle().key(Messages.LOG_INIT_CONFIGURATION_1, this)); 343 } 344 } 345 346 /** 347 * Loads the OpenCms configuration from the given XML file.<p> 348 * 349 * @throws SAXException in case of XML parse errors 350 * @throws IOException in case of file IO errors 351 */ 352 public void loadXmlConfiguration() throws SAXException, IOException { 353 354 URL baseUrl = m_baseFolder.toURI().toURL(); 355 if (LOG.isDebugEnabled()) { 356 LOG.debug(Messages.get().getBundle().key(Messages.LOG_BASE_URL_1, baseUrl)); 357 } 358 359 // first load the base configuration 360 loadXmlConfiguration(baseUrl, this); 361 362 // now iterate all sub-configurations 363 Iterator<I_CmsXmlConfiguration> i = m_configurations.iterator(); 364 while (i.hasNext()) { 365 loadXmlConfiguration(baseUrl, i.next()); 366 } 367 368 // remove the old backups 369 removeOldBackups(MAX_BACKUP_DAYS); 370 } 371 372 /** 373 * Sets the admin CmsObject.<p> 374 * 375 * @param cms the admin CmsObject 376 */ 377 public void setAdminCms(CmsObject cms) { 378 379 if (m_adminCms != null) { 380 LOG.error("Can not set admin CmsObject of configuration manager because it is already set."); 381 return; 382 } 383 for (I_CmsXmlConfiguration config : m_configurations) { 384 if (config instanceof I_CmsXmlConfigurationWithUpdateHandler) { 385 ((I_CmsXmlConfigurationWithUpdateHandler)config).setCmsObject(cms); 386 } 387 } 388 m_adminCms = cms; 389 } 390 391 /** 392 * Sets the configuration read from the <code>opencms.properties</code>.<p> 393 * 394 * @param propertyConfiguration the configuration read from the <code>opencms.properties</code> 395 * 396 * @see #getConfiguration() 397 */ 398 public void setConfiguration(CmsParameterConfiguration propertyConfiguration) { 399 400 m_propertyConfiguration = propertyConfiguration; 401 } 402 403 /** 404 * Writes the XML configuration for the provided configuration instance.<p> 405 * 406 * @param clazz the configuration class to write the XML for 407 * @throws IOException in case of I/O errors while writing 408 * @throws CmsConfigurationException if the given class is not a valid configuration class 409 */ 410 public void writeConfiguration(Class<?> clazz) throws IOException, CmsConfigurationException { 411 412 I_CmsXmlConfiguration configuration = getConfiguration(clazz); 413 if (configuration == null) { 414 throw new CmsConfigurationException( 415 Messages.get().container(Messages.ERR_CONFIG_WITH_UNKNOWN_CLASS_1, clazz.getName())); 416 } 417 418 // generate the file URL for the XML input 419 File file = new File(m_baseFolder, configuration.getXmlFileName()); 420 if (LOG.isDebugEnabled()) { 421 LOG.debug(Messages.get().getBundle().key(Messages.LOG_WRITE_CONFIG_XMLFILE_1, file.getAbsolutePath())); 422 } 423 424 // generate the XML document 425 Document config = generateXml(configuration); 426 427 // output the document 428 XMLWriter writer = null; 429 OutputFormat format = OutputFormat.createPrettyPrint(); 430 format.setIndentSize(4); 431 format.setTrimText(false); 432 format.setEncoding(CmsEncoder.ENCODING_UTF_8); 433 434 OutputStream out = null; 435 try { 436 out = new FileOutputStream(file); 437 writer = new XMLWriter(out, format); 438 writer.write(config); 439 writer.flush(); 440 } finally { 441 if (writer != null) { 442 writer.close(); 443 } 444 if (out != null) { 445 out.close(); 446 } 447 } 448 449 if (configuration instanceof I_CmsXmlConfigurationWithUpdateHandler) { 450 try { 451 LOG.info("Running configuration update handler for " + configuration.getClass().getName()); 452 ((I_CmsXmlConfigurationWithUpdateHandler)configuration).handleUpdate(); 453 LOG.info("Finished configuration update handler for " + configuration.getClass().getName()); 454 } catch (Exception e) { 455 LOG.error(e.getLocalizedMessage(), e); 456 } 457 } 458 459 if (LOG.isInfoEnabled()) { 460 LOG.info( 461 Messages.get().getBundle().key( 462 Messages.LOG_WRITE_CONFIG_SUCCESS_2, 463 file.getAbsolutePath(), 464 configuration.getClass().getName())); 465 } 466 467 } 468 469 /** 470 * Gets the path to the XSLT transformation file that should be used for the configuration.<p> 471 * 472 * @return the path to the XSLT transformation 473 */ 474 String getTransformationPath() { 475 476 String path = System.getProperty("opencms.config.transform"); 477 if (path == null) { 478 path = CmsStringUtil.joinPaths(m_baseFolder.getAbsolutePath(), DEFAULT_XSLT_FILENAME); 479 } 480 return path; 481 } 482 483 /** 484 * Checks if an XSLT transformation file is available.<p> 485 * 486 * @return true if an XSLT transformation file is available 487 */ 488 boolean hasTransformation() { 489 490 String transformationPath = getTransformationPath(); 491 boolean result = (transformationPath != null) && new File(transformationPath).exists(); 492 if (result) { 493 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_XSLT_CONFIG_ENABLED_1, transformationPath)); 494 } else { 495 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_XSLT_CONFIG_DISABLED_0)); 496 } 497 return result; 498 } 499 500 /** 501 * Transforms the given configuration using an XSLT transformation.<p> 502 * 503 * @param url the URL of the base folder 504 * @param config the configuration object 505 * 506 * @return the InputSource to feed the configuration digester 507 * 508 * @throws TransformerException if the transformation fails 509 * @throws IOException if an error occurs while reading the configuration or transformation 510 * @throws SAXException if parsing the configuration file fails 511 * @throws ParserConfigurationException if something goes wrong with configuring the parser 512 */ 513 InputSource transformConfiguration(URL url, I_CmsXmlConfiguration config) 514 throws TransformerException, IOException, SAXException, ParserConfigurationException { 515 516 String configPath = CmsStringUtil.joinPaths(url.getFile(), config.getXmlFileName()); 517 String transformPath = getTransformationPath(); 518 TransformerFactory factory = TransformerFactory.newInstance(); 519 520 ByteArrayOutputStream errBaos = new ByteArrayOutputStream(); 521 PrintStream oldErr = System.err; 522 System.setErr(new PrintStream(errBaos)); 523 try { 524 LOG.info("Transforming '" + configPath + "' with transformation '" + transformPath + "'"); 525 Transformer transformer = factory.newTransformer(new StreamSource(new File(transformPath))); 526 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); 527 transformer.setParameter("file", config.getXmlFileName()); 528 InetAddress localhost = InetAddress.getLocalHost(); 529 transformer.setParameter("hostName", localhost.getHostName()); 530 transformer.setParameter("canonicalHostName", localhost.getCanonicalHostName()); 531 transformer.setParameter("hostAddress", localhost.getHostAddress()); 532 // use a SAXSource here because we need to set the correct entity resolver to prevent errors 533 SAXParserFactory parserFactory = SAXParserFactory.newInstance(); 534 parserFactory.setNamespaceAware(true); 535 parserFactory.setValidating(false); // Turn off validation 536 XMLReader reader = parserFactory.newSAXParser().getXMLReader(); 537 reader.setEntityResolver(new CmsXmlEntityResolver(null)); 538 Source source = new SAXSource(reader, new InputSource(configPath)); 539 540 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 541 Result target = new StreamResult(baos); 542 543 transformer.transform(source, target); 544 545 byte[] transformedConfig = baos.toByteArray(); 546 // We can't set the doctype dynamically from inside the XSLT transform using XSLT 1.0, and XSLT 2.0 547 // isn't supported by the standard implementation in the JDK. So we do some macro replacement after the 548 // transformation. 549 String transformedConfigStr = new String(transformedConfig, "UTF-8").replaceFirst( 550 "@dtd@", 551 config.getDtdUrlPrefix() + config.getDtdFilename()); 552 if (LOG.isDebugEnabled()) { 553 LOG.debug(""); 554 LOG.debug( 555 "=================== Transformation result for config file '" + config.getXmlFileName() + "':"); 556 LOG.debug(transformedConfigStr); 557 } 558 return new InputSource(new ByteArrayInputStream(transformedConfigStr.getBytes("UTF-8"))); 559 } finally { 560 System.setErr(oldErr); 561 byte[] errorBytes = errBaos.toByteArray(); 562 if (errorBytes.length > 0) { 563 LOG.warn(new String(errorBytes, "UTF-8")); 564 } 565 } 566 } 567 568 /** 569 * Creates a backup of the given XML configurations input file.<p> 570 * 571 * @param configuration the configuration for which the input file should be backed up 572 */ 573 private void backupXmlConfiguration(I_CmsXmlConfiguration configuration) { 574 575 String fromName = m_baseFolder.getAbsolutePath() + File.separatorChar + configuration.getXmlFileName(); 576 String toDatePrefix = BACKUP_DATE_FORMAT.format(new Date()); 577 String toName = m_backupFolder.getAbsolutePath() 578 + File.separatorChar 579 + toDatePrefix 580 + configuration.getXmlFileName(); 581 582 if (LOG.isDebugEnabled()) { 583 LOG.debug(Messages.get().getBundle().key(Messages.LOG_CREATE_CONFIG_BKP_2, fromName, toName)); 584 } 585 586 try { 587 CmsFileUtil.copy(fromName, toName); 588 } catch (IOException e) { 589 LOG.error(Messages.get().getBundle().key(Messages.LOG_CREATE_CONFIG_BKP_FAILURE_1, toName), e); 590 } 591 } 592 593 /** 594 * Adds a new DTD system id prefix mapping for internal resolution of external URLs.<p> 595 * 596 * @param configuration the configuration to add the mapping from 597 */ 598 private void cacheDtdSystemId(I_CmsXmlConfiguration configuration) { 599 600 if (configuration.getDtdSystemLocation() != null) { 601 try { 602 String file = CmsFileUtil.readFile( 603 configuration.getDtdSystemLocation() + configuration.getDtdFilename(), 604 CmsEncoder.ENCODING_UTF_8); 605 CmsXmlEntityResolver.cacheSystemId( 606 configuration.getDtdUrlPrefix() + configuration.getDtdFilename(), 607 file.getBytes(CmsEncoder.ENCODING_UTF_8)); 608 if (LOG.isDebugEnabled()) { 609 LOG.debug( 610 Messages.get().getBundle().key( 611 Messages.LOG_CACHE_DTD_SYSTEM_ID_1, 612 configuration.getDtdUrlPrefix() 613 + configuration.getDtdFilename() 614 + " --> " 615 + configuration.getDtdSystemLocation() 616 + configuration.getDtdFilename())); 617 } 618 } catch (IOException e) { 619 LOG.error( 620 Messages.get().getBundle().key( 621 Messages.LOG_CACHE_DTD_SYSTEM_ID_FAILURE_1, 622 configuration.getDtdSystemLocation() + configuration.getDtdFilename()), 623 e); 624 } 625 } 626 } 627 628 /** 629 * Loads the OpenCms configuration from the given XML URL.<p> 630 * 631 * @param url the base URL of the XML configuration to load 632 * @param configuration the configuration to load 633 * @throws SAXException in case of XML parse errors 634 * @throws IOException in case of file IO errors 635 */ 636 private void loadXmlConfiguration(URL url, I_CmsXmlConfiguration configuration) throws SAXException, IOException { 637 638 // generate the file URL for the XML input 639 URL fileUrl = new URL(url, configuration.getXmlFileName()); 640 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOAD_CONFIG_XMLFILE_1, fileUrl)); 641 // Check transformation rule here so we have the XML file / XSLT file log output together 642 boolean hasTransformation = hasTransformation(); 643 644 // create a backup of the configuration 645 backupXmlConfiguration(configuration); 646 647 // instantiate Digester and enable XML validation 648 m_digester = new Digester(); 649 m_digester.setUseContextClassLoader(true); 650 //TODO: For this to work with transformed configurations, we need to add the correct DOCTYPE declarations to the transformed files 651 m_digester.setValidating(true); 652 m_digester.setEntityResolver(new CmsXmlEntityResolver(null)); 653 m_digester.setRuleNamespaceURI(null); 654 m_digester.setErrorHandler(new CmsXmlErrorHandler(fileUrl.getFile())); 655 656 // add this class to the Digester 657 m_digester.push(configuration); 658 659 configuration.addXmlDigesterRules(m_digester); 660 661 InputSource inputSource = null; 662 if (hasTransformation) { 663 try { 664 inputSource = transformConfiguration(url, configuration); 665 } catch (Exception e) { 666 LOG.error("Error transforming " + configuration.getXmlFileName() + ": " + e.getLocalizedMessage(), e); 667 } 668 } 669 if (inputSource == null) { 670 inputSource = new InputSource(fileUrl.openStream()); 671 } 672 // start the parsing process 673 m_digester.parse(inputSource); 674 } 675 676 /** 677 * Removes all backups that are older then the given number of days.<p> 678 * 679 * @param daysToKeep the days to keep the backups for 680 */ 681 private void removeOldBackups(long daysToKeep) { 682 683 long maxAge = (System.currentTimeMillis() - (daysToKeep * 24 * 60 * 60 * 1000)); 684 File[] files = m_backupFolder.listFiles(); 685 for (int i = 0; i < files.length; i++) { 686 File file = files[i]; 687 long lastMod = file.lastModified(); 688 if ((lastMod < maxAge) & (!file.getAbsolutePath().endsWith(CmsConfigurationManager.POSTFIX_ORI))) { 689 file.delete(); 690 if (LOG.isDebugEnabled()) { 691 LOG.debug( 692 Messages.get().getBundle().key(Messages.LOG_REMOVE_CONFIG_FILE_1, file.getAbsolutePath())); 693 } 694 } 695 } 696 } 697}