Index: cocoon-monitoring/src/main/java/org/apache/cocoon/monitoring/Log4JReconfigurator.java
===================================================================
--- cocoon-monitoring/src/main/java/org/apache/cocoon/monitoring/Log4JReconfigurator.java	(revision 774559)
+++ cocoon-monitoring/src/main/java/org/apache/cocoon/monitoring/Log4JReconfigurator.java	(working copy)
@@ -16,27 +16,65 @@
  */
 package org.apache.cocoon.monitoring;
 
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.List;
+import java.util.Scanner;
 
+import javax.naming.ConfigurationException;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.cocoon.configuration.PropertyHelper;
+import org.apache.cocoon.configuration.Settings;
+import org.apache.commons.io.FilenameUtils;
 import org.apache.log4j.Level;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
 import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.xml.Log4jEntityResolver;
 import org.springframework.jmx.export.annotation.ManagedAttribute;
 import org.springframework.jmx.export.annotation.ManagedOperation;
 import org.springframework.jmx.export.annotation.ManagedOperationParameter;
 import org.springframework.jmx.export.annotation.ManagedOperationParameters;
 import org.springframework.jmx.export.annotation.ManagedResource;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.helpers.DefaultHandler;
 
 @ManagedResource
 public class Log4JReconfigurator {
 
-    private LoggerRepository loggerRepository;
+    private static final String[] EXTENSIONS = new String[] { "xml", "properties" };
 
+    private final Logger logger;
+    private final LoggerRepository loggerRepository;
+    private final DocumentBuilder docBuilder;
+
+    private Settings settings;
+
     public Log4JReconfigurator() {
         this.loggerRepository = LogManager.getLoggerRepository();
+        this.logger = Logger.getLogger(Log4JReconfigurator.class);
+
+        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+        dbf.setValidating(true);
+
+        try {
+            this.docBuilder = dbf.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new RuntimeException(e);
+        }
+        this.docBuilder.setErrorHandler(new DefaultHandler());
+        this.docBuilder.setEntityResolver(new Log4jEntityResolver());
     }
 
     @ManagedAttribute(description = "Return a list of all configured loggers with their level.")
@@ -55,10 +93,13 @@
         return result.toArray(new String[] {});
     }
 
-    @ManagedOperation(description = "Sets logging level for a paticular package or a class. Returns true if operation was succesful.")
+    @ManagedOperation(description = "Sets logging level for a paticular package or a class. Returns "
+            + "true if operation was succesful.")
     @ManagedOperationParameters(value = {
-            @ManagedOperationParameter(name = "category", description = "Name of the log category (usually a package or class name) whose log level should be changed."),
-            @ManagedOperationParameter(name = "newLevel", description = "New log level for that category. Avaliable log levels are: OFF, INFO, WARN, ERROR, FATAL, TRACE, DEBUG, ALL") })
+            @ManagedOperationParameter(name = "category", description = "Name of the log category (usually "
+                    + "a package or class name) whose log level should be changed."),
+            @ManagedOperationParameter(name = "newLevel", description = "New log level for that category. "
+                    + "Avaliable log levels are: OFF, INFO, WARN, ERROR, FATAL, TRACE, DEBUG, ALL") })
     public boolean setLoggingLevel(String category, String newLogLevel) {
         boolean result = false;
 
@@ -71,11 +112,16 @@
         return result;
     }
 
-    @ManagedOperation(description = "Sets new logging level for amout of time. After timeout log level is set back to old value.")
+    @ManagedOperation(description = "Sets new logging level for amout of time. After timeout log level is set"
+            + " back to old value.")
     @ManagedOperationParameters(value = {
-            @ManagedOperationParameter(name = "category", description = "Name of the log category (usually a package or class name) whose log level should be changed."),
-            @ManagedOperationParameter(name = "temporalLevel", description = "Temporal log level for that category that should be set for specified amout of time."),
-            @ManagedOperationParameter(name = "timeOut", description = "Amount of time that temporalLevel should be active. Value of timeOut should match regex: ^[0-9.]+[dhm]?$ where 'd' means day, 'h' hours and 'm' minutes") })
+            @ManagedOperationParameter(name = "category", description = "Name of the log category (usually"
+                    + " a package or class name) whose log level should be changed."),
+            @ManagedOperationParameter(name = "temporalLevel", description = "Temporal log level for that "
+                    + "category that should be set for specified amout of time."),
+            @ManagedOperationParameter(name = "timeOut", description = "Amount of time that temporalLevel "
+                    + "should be active. Value of timeOut should match regex: ^[0-9.]+[dhm]?$ where 'd' means "
+                    + "day, 'h' hours and 'm' minutes") })
     public boolean setLoggingTempoporalLevel(String category, String temporalLogLevel, String timeOut) {
         if (!timeOut.matches("^[0-9.]+[dhm]?$")) {
             throw new UnsupportedOperationException("Unsupported time out format: " + timeOut);
@@ -94,4 +140,132 @@
 
         return result;
     }
+
+    @ManagedOperation(description = "Allows to change configuration of log4j in fly. This function support "
+            + "both XML and properties configuration files. Before reloading configuration it checks that new "
+            + "config file contains at least one appender and all output files are accessible (for XML configs it"
+            + "also validate XML syntax using schema od DTD)")
+    @ManagedOperationParameters(value = { @ManagedOperationParameter(name = "configFilePatch", description = "Absolute patch to configuration file.") })
+    public boolean loadNewConfigurationFile(String patch) throws Exception {
+        patch = patch.trim();
+
+        // check extension
+        if (FilenameUtils.isExtension(patch, EXTENSIONS)) {
+            File newConfig = new File(patch);
+
+            if (!newConfig.exists()) {
+                this.logger.fatal("Can not find file: " + patch);
+                throw new FileNotFoundException("Can not find file: " + patch);
+            } else if (!newConfig.canRead()) {
+                logAndThrowIOException("Can not read file: " + patch);
+            }
+
+            if (FilenameUtils.isExtension(patch, "xml")) {
+                loadNewXMLConfigurationFile(patch);
+            } else {
+                loadNewPropertiesConfigurationFile(patch);
+            }
+        } else {
+            throw new ConfigurationException("Unsuported file format: " + FilenameUtils.getExtension(patch));
+        }
+        return true;
+    }
+
+    /**
+     * Inject the settings object.
+     *
+     * @param s The settings bean.
+     */
+    public void setSettings(final Settings s) {
+        this.settings = s;
+    }
+
+    /**
+     * Loads XML config file specified by <code>patch</code> parameter.
+     * Then this file is validate against DTD or schema, after that every
+     * appender is check that it output file is accessible.
+     *
+     * @param patch Absolute patch to XML configuration file.
+     * @throws Exception
+     */
+    private void loadNewXMLConfigurationFile(String patch) throws Exception {
+        Document doc;
+        try { // validate XML config file
+            doc = this.docBuilder.parse(patch);
+        } catch (Exception e) {
+            this.logger.fatal(e.getMessage(), e);
+            throw new IOException("Config file parse exception: " + e.getMessage());
+        }
+
+        // check access for all log files
+        NodeList appenderList = doc.getElementsByTagName("appender");
+        for (int i = 0; i < appenderList.getLength(); i++) {
+            NodeList childNodes = appenderList.item(i).getChildNodes();
+            for (int j = 0; j < childNodes.getLength(); j++) {
+                Node item = childNodes.item(j);
+                extractLogFilesPatchAndValidate(item);
+            }
+        }
+
+        // apply new settings
+        DOMConfigurator.configure(patch);
+    }
+
+    private void extractLogFilesPatchAndValidate(Node item) throws IOException {
+        if (item.getNodeName().equalsIgnoreCase("param")) {
+            NamedNodeMap itemAttributes = item.getAttributes();
+            if (itemAttributes != null) {
+                Node paramName = itemAttributes.getNamedItem("name");
+                if (paramName != null && paramName.getNodeValue().equalsIgnoreCase("file")) {
+                    Node paramValue = itemAttributes.getNamedItem("value");
+                    if (paramValue != null) {
+                        String logPatch = paramValue.getNodeValue();
+                        validateLogFile(logPatch);
+                    }
+                }
+            }
+        }
+    }
+
+    private void loadNewPropertiesConfigurationFile(String patch) throws ConfigurationException, IOException {
+        boolean result = false;
+        File file = new File(patch);
+        // search for appender configuration
+        Scanner fileScanner = new Scanner(file);
+        while (fileScanner.hasNext()) {
+            String line = fileScanner.nextLine();
+            if (!result && line.toLowerCase().matches("^log4j\\.appender\\.[\\w\\.]+=[\\w\\.]+$")) {
+                PropertyConfigurator.configure(file.getPath());
+                result = true; // we got our "at least one appender" ;)
+            }
+
+            if (line.toLowerCase().matches("^log4j\\.appender\\.[\\w]+\\.file=[\\w\\.\\{\\}\\$/\\:]+$")) {
+                String[] logFile = line.split("=");
+                validateLogFile(logFile[1]);
+            }
+        }
+        if (!result) {
+            throw new ConfigurationException(
+                    "No configured appenders, there should be at least one appender confgured.");
+        }
+    }
+
+    private void logAndThrowIOException(String message) throws IOException {
+        this.logger.fatal(message);
+        throw new IOException(message);
+    }
+
+    private void validateLogFile(String logPatch) throws IOException {
+        String logDirPatch = FilenameUtils.getFullPath(PropertyHelper.replace(logPatch, this.settings));
+
+        if (logDirPatch.length() == 0) { // if logDirPatch is empty
+            logDirPatch = "."; // current directory is log directory
+        }
+
+        if (!new File(logDirPatch).exists()) {
+            logAndThrowIOException("Log directory: " + logDirPatch + " does not exist.");
+        } else if (!new File(logPatch).canWrite()) {
+            logAndThrowIOException("Log file: " + logPatch + " is read only.");
+        }
+    }
 }
Index: cocoon-monitoring/src/main/resources/META-INF/cocoon/spring/cocoon-monitoring.xml
===================================================================
--- cocoon-monitoring/src/main/resources/META-INF/cocoon/spring/cocoon-monitoring.xml	(revision 774559)
+++ cocoon-monitoring/src/main/resources/META-INF/cocoon/spring/cocoon-monitoring.xml	(working copy)
@@ -39,5 +39,7 @@
   </bean>
   
   <bean id="org.apache.cocoon.monitoring.Log4JReconfigurator"
-    class="org.apache.cocoon.monitoring.Log4JReconfigurator" scope="singleton" />
+    class="org.apache.cocoon.monitoring.Log4JReconfigurator" scope="singleton">
+    <property name="settings" ref="org.apache.cocoon.configuration.Settings" />
+  </bean>
 </beans>
