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