Sort members.
diff --git a/src/main/java/org/apache/commons/configuration2/io/FileHandler.java b/src/main/java/org/apache/commons/configuration2/io/FileHandler.java
index 9aee68e..8d87a9f 100644
--- a/src/main/java/org/apache/commons/configuration2/io/FileHandler.java
+++ b/src/main/java/org/apache/commons/configuration2/io/FileHandler.java
@@ -118,6 +118,45 @@
  */
 public class FileHandler
 {
+    /**
+     * An internal class that performs all update operations of the handler's
+     * {@code FileLocator} in a safe way even if there is concurrent access.
+     * This class implements anon-blocking algorithm for replacing the immutable
+     * {@code FileLocator} instance stored in an atomic reference by a
+     * manipulated instance. (If we already had lambdas, this could be done
+     * without a class in a more elegant way.)
+     */
+    private abstract class Updater
+    {
+        /**
+         * Performs an update of the enclosing file handler's
+         * {@code FileLocator} object.
+         */
+        public void update()
+        {
+            boolean done;
+            do
+            {
+                final FileLocator oldLocator = fileLocator.get();
+                final FileLocatorBuilder builder =
+                        FileLocatorUtils.fileLocator(oldLocator);
+                updateBuilder(builder);
+                done = fileLocator.compareAndSet(oldLocator, builder.create());
+            } while (!done);
+            fireLocationChangedEvent();
+        }
+
+        /**
+         * Updates the passed in builder object to apply the manipulation to be
+         * performed by this {@code Updater}. The builder has been setup with
+         * the former content of the {@code FileLocator} to be manipulated.
+         *
+         * @param builder the builder for creating an updated
+         *        {@code FileLocator}
+         */
+        protected abstract void updateBuilder(FileLocatorBuilder builder);
+    }
+
     /** Constant for the URI scheme for files. */
     private static final String FILE_SCHEME = "file:";
 
@@ -134,7 +173,13 @@
             new SynchronizerSupport()
             {
                 @Override
-                public void unlock(final LockMode mode)
+                public Synchronizer getSynchronizer()
+                {
+                    return NoOpSynchronizer.INSTANCE;
+                }
+
+                @Override
+                public void lock(final LockMode mode)
                 {
                 }
 
@@ -144,17 +189,117 @@
                 }
 
                 @Override
-                public void lock(final LockMode mode)
+                public void unlock(final LockMode mode)
                 {
                 }
-
-                @Override
-                public Synchronizer getSynchronizer()
-                {
-                    return NoOpSynchronizer.INSTANCE;
-                }
             };
 
+    /**
+     * Helper method for checking a file handler which is to be copied. Throws
+     * an exception if the handler is <b>null</b>.
+     *
+     * @param c the {@code FileHandler} from which to copy the location
+     * @return the same {@code FileHandler}
+     */
+    private static FileHandler checkSourceHandler(final FileHandler c)
+    {
+        if (c == null)
+        {
+            throw new IllegalArgumentException(
+                    "FileHandler to assign must not be null!");
+        }
+        return c;
+    }
+
+    /**
+     * A helper method for closing a stream. Occurring exceptions will be
+     * ignored.
+     *
+     * @param cl the stream to be closed (may be <b>null</b>)
+     */
+    private static void closeSilent(final Closeable cl)
+    {
+        try
+        {
+            if (cl != null)
+            {
+                cl.close();
+            }
+        }
+        catch (final IOException e)
+        {
+            LogFactory.getLog(FileHandler.class).warn("Exception when closing " + cl, e);
+        }
+    }
+
+    /**
+     * Creates a {@code File} object from the content of the given
+     * {@code FileLocator} object. If the locator is not defined, result is
+     * <b>null</b>.
+     *
+     * @param loc the {@code FileLocator}
+     * @return a {@code File} object pointing to the associated file
+     */
+    private static File createFile(final FileLocator loc)
+    {
+        if (loc.getFileName() == null && loc.getSourceURL() == null)
+        {
+            return null;
+        }
+        else if (loc.getSourceURL() != null)
+        {
+            return FileLocatorUtils.fileFromURL(loc.getSourceURL());
+        }
+        else
+        {
+            return FileLocatorUtils.getFile(loc.getBasePath(),
+                    loc.getFileName());
+        }
+    }
+
+    /**
+     * Creates an uninitialized file locator.
+     *
+     * @return the locator
+     */
+    private static FileLocator emptyFileLocator()
+    {
+        return FileLocatorUtils.fileLocator().create();
+    }
+
+    /**
+     * Creates a new {@code FileHandler} instance from properties stored in a
+     * map. This method tries to extract a {@link FileLocator} from the map. A
+     * new {@code FileHandler} is created based on this {@code FileLocator}.
+     *
+     * @param map the map (may be <b>null</b>)
+     * @return the newly created {@code FileHandler}
+     * @see FileLocatorUtils#fromMap(Map)
+     */
+    public static FileHandler fromMap(final Map<String, ?> map)
+    {
+        return new FileHandler(null, FileLocatorUtils.fromMap(map));
+    }
+
+    /**
+     * Normalizes URLs to files. Ensures that file URLs start with the correct
+     * protocol.
+     *
+     * @param fileName the string to be normalized
+     * @return the normalized file URL
+     */
+    private static String normalizeFileURL(String fileName)
+    {
+        if (fileName != null && fileName.startsWith(FILE_SCHEME)
+                && !fileName.startsWith(FILE_SCHEME_SLASH))
+        {
+            fileName =
+                    FILE_SCHEME_SLASH
+                            + fileName.substring(FILE_SCHEME.length());
+        }
+        return fileName;
+    }
+
     /** The file-based object managed by this handler. */
     private final FileBased content;
 
@@ -219,31 +364,6 @@
     }
 
     /**
-     * Creates a new {@code FileHandler} instance from properties stored in a
-     * map. This method tries to extract a {@link FileLocator} from the map. A
-     * new {@code FileHandler} is created based on this {@code FileLocator}.
-     *
-     * @param map the map (may be <b>null</b>)
-     * @return the newly created {@code FileHandler}
-     * @see FileLocatorUtils#fromMap(Map)
-     */
-    public static FileHandler fromMap(final Map<String, ?> map)
-    {
-        return new FileHandler(null, FileLocatorUtils.fromMap(map));
-    }
-
-    /**
-     * Returns the {@code FileBased} object associated with this
-     * {@code FileHandler}.
-     *
-     * @return the associated {@code FileBased} object
-     */
-    public final FileBased getContent()
-    {
-        return content;
-    }
-
-    /**
      * Adds a listener to this {@code FileHandler}. It is notified about
      * property changes and IO operations.
      *
@@ -260,62 +380,140 @@
     }
 
     /**
-     * Removes the specified listener from this object.
+     * Checks whether a content object is available. If not, an exception is
+     * thrown. This method is called whenever the content object is accessed.
      *
-     * @param l the listener to be removed
+     * @throws ConfigurationException if not content object is defined
      */
-    public void removeFileHandlerListener(final FileHandlerListener l)
+    private void checkContent() throws ConfigurationException
     {
-        listeners.remove(l);
+        if (getContent() == null)
+        {
+            throw new ConfigurationException("No content available!");
+        }
     }
 
     /**
-     * Return the name of the file. If only a URL is defined, the file name
-     * is derived from there.
+     * Checks whether a content object is available and returns the current
+     * {@code FileLocator}. If there is no content object, an exception is
+     * thrown. This is a typical operation to be performed before a load() or
+     * save() operation.
      *
-     * @return the file name
+     * @return the current {@code FileLocator} to be used for the calling
+     *         operation
      */
-    public String getFileName()
+    private FileLocator checkContentAndGetLocator()
+            throws ConfigurationException
     {
-        final FileLocator locator = getFileLocator();
-        if (locator.getFileName() != null)
-        {
-            return locator.getFileName();
-        }
-
-        if (locator.getSourceURL() != null)
-        {
-            return FileLocatorUtils.getFileName(locator.getSourceURL());
-        }
-
-        return null;
+        checkContent();
+        return getFileLocator();
     }
 
     /**
-     * Set the name of the file. The passed in file name can contain a relative
-     * path. It must be used when referring files with relative paths from
-     * classpath. Use {@code setPath()} to set a full qualified file name. The
-     * URL is set to <b>null</b> as it has to be determined anew based on the
-     * file name and the base path.
-     *
-     * @param fileName the name of the file
+     * Clears the location of this {@code FileHandler}. Afterwards this handler
+     * does not point to any valid file.
      */
-    public void setFileName(final String fileName)
+    public void clearLocation()
     {
-        final String name = normalizeFileURL(fileName);
         new Updater()
         {
             @Override
             protected void updateBuilder(final FileLocatorBuilder builder)
             {
-                builder.fileName(name);
-                builder.sourceURL(null);
+                builder.basePath(null).fileName(null).sourceURL(null);
             }
         }
         .update();
     }
 
     /**
+     * Creates a {@code FileLocator} which is a copy of the passed in one, but
+     * has the given file name set to reference the target file.
+     *
+     * @param fileName the file name
+     * @param locator the {@code FileLocator} to copy
+     * @return the manipulated {@code FileLocator} with the file name
+     */
+    private FileLocator createLocatorWithFileName(final String fileName,
+            final FileLocator locator)
+    {
+        return FileLocatorUtils.fileLocator(locator).sourceURL(null)
+                .fileName(fileName).create();
+    }
+
+    /**
+     * Obtains a {@code SynchronizerSupport} for the current content. If the
+     * content implements this interface, it is returned. Otherwise, result is a
+     * dummy object. This method is called before load and save operations. The
+     * returned object is used for synchronization.
+     *
+     * @return the {@code SynchronizerSupport} for synchronization
+     */
+    private SynchronizerSupport fetchSynchronizerSupport()
+    {
+        if (getContent() instanceof SynchronizerSupport)
+        {
+            return (SynchronizerSupport) getContent();
+        }
+        return DUMMY_SYNC_SUPPORT;
+    }
+
+    /**
+     * Notifies the registered listeners about a completed load operation.
+     */
+    private void fireLoadedEvent()
+    {
+        for (final FileHandlerListener l : listeners)
+        {
+            l.loaded(this);
+        }
+    }
+
+    /**
+     * Notifies the registered listeners about the start of a load operation.
+     */
+    private void fireLoadingEvent()
+    {
+        for (final FileHandlerListener l : listeners)
+        {
+            l.loading(this);
+        }
+    }
+
+    /**
+     * Notifies the registered listeners about a property update.
+     */
+    private void fireLocationChangedEvent()
+    {
+        for (final FileHandlerListener l : listeners)
+        {
+            l.locationChanged(this);
+        }
+    }
+
+    /**
+     * Notifies the registered listeners about a completed save operation.
+     */
+    private void fireSavedEvent()
+    {
+        for (final FileHandlerListener l : listeners)
+        {
+            l.saved(this);
+        }
+    }
+
+    /**
+     * Notifies the registered listeners about the start of a save operation.
+     */
+    private void fireSavingEvent()
+    {
+        for (final FileHandlerListener l : listeners)
+        {
+            l.saving(this);
+        }
+    }
+
+    /**
      * Return the base path. If no base path is defined, but a URL, the base
      * path is derived from there.
      *
@@ -338,34 +536,25 @@
     }
 
     /**
-     * Sets the base path. The base path is typically either a path to a
-     * directory or a URL. Together with the value passed to the
-     * {@code setFileName()} method it defines the location of the configuration
-     * file to be loaded. The strategies for locating the file are quite
-     * tolerant. For instance if the file name is already an absolute path or a
-     * fully defined URL, the base path will be ignored. The base path can also
-     * be a URL, in which case the file name is interpreted in this URL's
-     * context. If other methods are used for determining the location of the
-     * associated file (e.g. {@code setFile()} or {@code setURL()}), the base
-     * path is automatically set. Setting the base path using this method
-     * automatically sets the URL to <b>null</b> because it has to be
-     * determined anew based on the file name and the base path.
+     * Returns the {@code FileBased} object associated with this
+     * {@code FileHandler}.
      *
-     * @param basePath the base path.
+     * @return the associated {@code FileBased} object
      */
-    public void setBasePath(final String basePath)
+    public final FileBased getContent()
     {
-        final String path = normalizeFileURL(basePath);
-        new Updater()
-        {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
-            {
-                builder.basePath(path);
-                builder.sourceURL(null);
-            }
-        }
-        .update();
+        return content;
+    }
+
+    /**
+     * Returns the encoding of the associated file. Result can be <b>null</b> if
+     * no encoding has been set.
+     *
+     * @return the encoding of the associated file
+     */
+    public String getEncoding()
+    {
+        return getFileLocator().getEncoding();
     }
 
     /**
@@ -382,28 +571,65 @@
     }
 
     /**
-     * Sets the location of the associated file as a {@code File} object. The
-     * passed in {@code File} is made absolute if it is not yet. Then the file's
-     * path component becomes the base path and its name component becomes the
-     * file name.
+     * Returns a {@code FileLocator} object with the specification of the file
+     * stored by this {@code FileHandler}. Note that this method returns the
+     * internal data managed by this {@code FileHandler} as it was defined.
+     * This is not necessarily the same as the data returned by the single
+     * access methods like {@code getFileName()} or {@code getURL()}: These
+     * methods try to derive missing data from other values that have been set.
      *
-     * @param file the location of the associated file
+     * @return a {@code FileLocator} with the referenced file
      */
-    public void setFile(final File file)
+    public FileLocator getFileLocator()
     {
-        final String fileName = file.getName();
-        final String basePath =
-                file.getParentFile() != null ? file.getParentFile()
-                        .getAbsolutePath() : null;
-        new Updater()
+        return fileLocator.get();
+    }
+
+    /**
+     * Return the name of the file. If only a URL is defined, the file name
+     * is derived from there.
+     *
+     * @return the file name
+     */
+    public String getFileName()
+    {
+        final FileLocator locator = getFileLocator();
+        if (locator.getFileName() != null)
         {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
-            {
-                builder.fileName(fileName).basePath(basePath).sourceURL(null);
-            }
+            return locator.getFileName();
         }
-        .update();
+
+        if (locator.getSourceURL() != null)
+        {
+            return FileLocatorUtils.getFileName(locator.getSourceURL());
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns the {@code FileSystem} to be used by this object when locating
+     * files. Result is never <b>null</b>; if no file system has been set, the
+     * default file system is returned.
+     *
+     * @return the used {@code FileSystem}
+     */
+    public FileSystem getFileSystem()
+    {
+        return FileLocatorUtils.obtainFileSystem(getFileLocator());
+    }
+
+    /**
+     * Returns the {@code FileLocationStrategy} to be applied when accessing the
+     * associated file. This method never returns <b>null</b>. If a
+     * {@code FileLocationStrategy} has been set, it is returned. Otherwise,
+     * result is the default {@code FileLocationStrategy}.
+     *
+     * @return the {@code FileLocationStrategy} to be used
+     */
+    public FileLocationStrategy getLocationStrategy()
+    {
+        return FileLocatorUtils.obtainLocationStrategy(getFileLocator());
     }
 
     /**
@@ -423,21 +649,6 @@
     }
 
     /**
-     * Sets the location of the associated file as a full or relative path name.
-     * The passed in path should represent a valid file name on the file system.
-     * It must not be used to specify relative paths for files that exist in
-     * classpath, either plain file system or compressed archive, because this
-     * method expands any relative path to an absolute one which may end in an
-     * invalid absolute path for classpath references.
-     *
-     * @param path the full path name of the associated file
-     */
-    public void setPath(final String path)
-    {
-        setFile(new File(path));
-    }
-
-    /**
      * Returns the location of the associated file as a URL. If a URL is set,
      * it is directly returned. Otherwise, an attempt to locate the referenced
      * file is made.
@@ -453,61 +664,44 @@
     }
 
     /**
-     * Sets the location of the associated file as a URL. For loading this can
-     * be an arbitrary URL with a supported protocol. If the file is to be
-     * saved, too, a URL with the &quot;file&quot; protocol should be provided.
-     * This method sets the file name and the base path to <b>null</b>.
-     * They have to be determined anew based on the new URL.
+     * Injects a {@code FileLocator} pointing to the specified URL if the
+     * current {@code FileBased} object implements the {@code FileLocatorAware}
+     * interface.
      *
-     * @param url the location of the file as URL
+     * @param url the URL for the locator
      */
-    public void setURL(final URL url)
+    private void injectFileLocator(final URL url)
     {
-        new Updater()
+        if (url == null)
         {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
+            injectNullFileLocator();
+        }
+        else
+        {
+            if (getContent() instanceof FileLocatorAware)
             {
-                builder.sourceURL(url);
-                builder.basePath(null).fileName(null);
+                final FileLocator locator =
+                        prepareNullLocatorBuilder().sourceURL(url).create();
+                ((FileLocatorAware) getContent()).initFileLocator(locator);
             }
         }
-        .update();
     }
 
     /**
-     * Returns a {@code FileLocator} object with the specification of the file
-     * stored by this {@code FileHandler}. Note that this method returns the
-     * internal data managed by this {@code FileHandler} as it was defined.
-     * This is not necessarily the same as the data returned by the single
-     * access methods like {@code getFileName()} or {@code getURL()}: These
-     * methods try to derive missing data from other values that have been set.
-     *
-     * @return a {@code FileLocator} with the referenced file
+     * Checks whether the associated {@code FileBased} object implements the
+     * {@code FileLocatorAware} interface. If this is the case, a
+     * {@code FileLocator} instance is injected which returns only <b>null</b>
+     * values. This method is called if no file location is available (e.g. if
+     * data is to be loaded from a stream). The encoding of the injected locator
+     * is derived from this object.
      */
-    public FileLocator getFileLocator()
+    private void injectNullFileLocator()
     {
-        return fileLocator.get();
-    }
-
-    /**
-     * Sets the file to be accessed by this {@code FileHandler} as a
-     * {@code FileLocator} object.
-     *
-     * @param locator the {@code FileLocator} with the definition of the file to
-     *        be accessed (must not be <b>null</b>
-     * @throws IllegalArgumentException if the {@code FileLocator} is
-     *         <b>null</b>
-     */
-    public void setFileLocator(final FileLocator locator)
-    {
-        if (locator == null)
+        if (getContent() instanceof FileLocatorAware)
         {
-            throw new IllegalArgumentException("FileLocator must not be null!");
+            final FileLocator locator = prepareNullLocatorBuilder().create();
+            ((FileLocatorAware) getContent()).initFileLocator(locator);
         }
-
-        fileLocator.set(locator);
-        fireLocationChangedEvent();
     }
 
     /**
@@ -521,176 +715,6 @@
     }
 
     /**
-     * Clears the location of this {@code FileHandler}. Afterwards this handler
-     * does not point to any valid file.
-     */
-    public void clearLocation()
-    {
-        new Updater()
-        {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
-            {
-                builder.basePath(null).fileName(null).sourceURL(null);
-            }
-        }
-        .update();
-    }
-
-    /**
-     * Returns the encoding of the associated file. Result can be <b>null</b> if
-     * no encoding has been set.
-     *
-     * @return the encoding of the associated file
-     */
-    public String getEncoding()
-    {
-        return getFileLocator().getEncoding();
-    }
-
-    /**
-     * Sets the encoding of the associated file. The encoding applies if binary
-     * files are loaded. Note that in this case setting an encoding is
-     * recommended; otherwise the platform's default encoding is used.
-     *
-     * @param encoding the encoding of the associated file
-     */
-    public void setEncoding(final String encoding)
-    {
-        new Updater()
-        {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
-            {
-                builder.encoding(encoding);
-            }
-        }
-        .update();
-    }
-
-    /**
-     * Returns the {@code FileSystem} to be used by this object when locating
-     * files. Result is never <b>null</b>; if no file system has been set, the
-     * default file system is returned.
-     *
-     * @return the used {@code FileSystem}
-     */
-    public FileSystem getFileSystem()
-    {
-        return FileLocatorUtils.obtainFileSystem(getFileLocator());
-    }
-
-    /**
-     * Sets the {@code FileSystem} to be used by this object when locating
-     * files. If a <b>null</b> value is passed in, the file system is reset to
-     * the default file system.
-     *
-     * @param fileSystem the {@code FileSystem}
-     */
-    public void setFileSystem(final FileSystem fileSystem)
-    {
-        new Updater()
-        {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
-            {
-                builder.fileSystem(fileSystem);
-            }
-        }
-        .update();
-    }
-
-    /**
-     * Resets the {@code FileSystem} used by this object. It is set to the
-     * default file system.
-     */
-    public void resetFileSystem()
-    {
-        setFileSystem(null);
-    }
-
-    /**
-     * Returns the {@code FileLocationStrategy} to be applied when accessing the
-     * associated file. This method never returns <b>null</b>. If a
-     * {@code FileLocationStrategy} has been set, it is returned. Otherwise,
-     * result is the default {@code FileLocationStrategy}.
-     *
-     * @return the {@code FileLocationStrategy} to be used
-     */
-    public FileLocationStrategy getLocationStrategy()
-    {
-        return FileLocatorUtils.obtainLocationStrategy(getFileLocator());
-    }
-
-    /**
-     * Sets the {@code FileLocationStrategy} to be applied when accessing the
-     * associated file. The strategy is stored in the underlying
-     * {@link FileLocator}. The argument can be <b>null</b>; this causes the
-     * default {@code FileLocationStrategy} to be used.
-     *
-     * @param strategy the {@code FileLocationStrategy}
-     * @see FileLocatorUtils#DEFAULT_LOCATION_STRATEGY
-     */
-    public void setLocationStrategy(final FileLocationStrategy strategy)
-    {
-        new Updater()
-        {
-            @Override
-            protected void updateBuilder(final FileLocatorBuilder builder)
-            {
-                builder.locationStrategy(strategy);
-            }
-
-        }
-        .update();
-    }
-
-    /**
-     * Locates the referenced file if necessary and ensures that the associated
-     * {@link FileLocator} is fully initialized. When accessing the referenced
-     * file the information stored in the associated {@code FileLocator} is
-     * used. If this information is incomplete (e.g. only the file name is set),
-     * an attempt to locate the file may have to be performed on each access. By
-     * calling this method such an attempt is performed once, and the results of
-     * a successful localization are stored. Hence, later access to the
-     * referenced file can be more efficient. Also, all properties pointing to
-     * the referenced file in this object's {@code FileLocator} are set (i.e.
-     * the URL, the base path, and the file name). If the referenced file cannot
-     * be located, result is <b>false</b>. This means that the information in
-     * the current {@code FileLocator} is insufficient or wrong. If the
-     * {@code FileLocator} is already fully defined, it is not changed.
-     *
-     * @return a flag whether the referenced file could be located successfully
-     * @see FileLocatorUtils#fullyInitializedLocator(FileLocator)
-     */
-    public boolean locate()
-    {
-        boolean result;
-        boolean done;
-
-        do
-        {
-            final FileLocator locator = getFileLocator();
-            FileLocator fullLocator =
-                    FileLocatorUtils.fullyInitializedLocator(locator);
-            if (fullLocator == null)
-            {
-                result = false;
-                fullLocator = locator;
-            }
-            else
-            {
-                result =
-                        fullLocator != locator
-                                || FileLocatorUtils.isFullyInitialized(locator);
-            }
-            done = fileLocator.compareAndSet(locator, fullLocator);
-        } while (!done);
-
-        return result;
-    }
-
-    /**
      * Loads the associated file from the underlying location. If no location
      * has been set, an exception is thrown.
      *
@@ -702,20 +726,6 @@
     }
 
     /**
-     * Loads the associated file from the given file name. The file name is
-     * interpreted in the context of the already set location (e.g. if it is a
-     * relative file name, a base path is applied if available). The underlying
-     * location is not changed.
-     *
-     * @param fileName the name of the file to be loaded
-     * @throws ConfigurationException if an error occurs
-     */
-    public void load(final String fileName) throws ConfigurationException
-    {
-        load(fileName, checkContentAndGetLocator());
-    }
-
-    /**
      * Loads the associated file from the specified {@code File}.
      *
      * @param file the file to load
@@ -738,15 +748,16 @@
     }
 
     /**
-     * Loads the associated file from the specified URL. The location stored in
-     * this object is not changed.
+     * Internal helper method for loading the associated file from the location
+     * specified in the given {@code FileLocator}.
      *
-     * @param url the URL of the file to be loaded
+     * @param locator the current {@code FileLocator}
      * @throws ConfigurationException if an error occurs
      */
-    public void load(final URL url) throws ConfigurationException
+    private void load(final FileLocator locator) throws ConfigurationException
     {
-        load(url, checkContentAndGetLocator());
+        final URL url = FileLocatorUtils.locateOrThrow(locator);
+        load(url, locator);
     }
 
     /**
@@ -763,6 +774,19 @@
     }
 
     /**
+     * Internal helper method for loading a file from the given input stream.
+     *
+     * @param in the input stream
+     * @param locator the current {@code FileLocator}
+     * @throws ConfigurationException if an error occurs
+     */
+    private void load(final InputStream in, final FileLocator locator)
+            throws ConfigurationException
+    {
+        load(in, locator.getEncoding());
+    }
+
+    /**
      * Loads the associated file from the specified stream, using the specified
      * encoding. If the encoding is <b>null</b>, the default encoding is used.
      *
@@ -793,186 +817,47 @@
     }
 
     /**
-     * Saves the associated file to the current location set for this object.
-     * Before this method can be called a valid location must have been set.
+     * Loads the associated file from the given file name. The file name is
+     * interpreted in the context of the already set location (e.g. if it is a
+     * relative file name, a base path is applied if available). The underlying
+     * location is not changed.
      *
-     * @throws ConfigurationException if an error occurs or no location has been
-     *         set yet
+     * @param fileName the name of the file to be loaded
+     * @throws ConfigurationException if an error occurs
      */
-    public void save() throws ConfigurationException
+    public void load(final String fileName) throws ConfigurationException
     {
-        save(checkContentAndGetLocator());
+        load(fileName, checkContentAndGetLocator());
     }
 
     /**
-     * Saves the associated file to the specified file name. This does not
-     * change the location of this object (use {@link #setFileName(String)} if
-     * you need it).
+     * Internal helper method for loading a file from a file name.
      *
      * @param fileName the file name
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    public void save(final String fileName) throws ConfigurationException
-    {
-        save(fileName, checkContentAndGetLocator());
-    }
-
-    /**
-     * Saves the associated file to the specified URL. This does not change the
-     * location of this object (use {@link #setURL(URL)} if you need it).
-     *
-     * @param url the URL
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    public void save(final URL url) throws ConfigurationException
-    {
-        save(url, checkContentAndGetLocator());
-    }
-
-    /**
-     * Saves the associated file to the specified {@code File}. The file is
-     * created automatically if it doesn't exist. This does not change the
-     * location of this object (use {@link #setFile} if you need it).
-     *
-     * @param file the target file
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    public void save(final File file) throws ConfigurationException
-    {
-        save(file, checkContentAndGetLocator());
-    }
-
-    /**
-     * Saves the associated file to the specified stream using the encoding
-     * returned by {@link #getEncoding()}.
-     *
-     * @param out the output stream
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    public void save(final OutputStream out) throws ConfigurationException
-    {
-        save(out, checkContentAndGetLocator());
-    }
-
-    /**
-     * Saves the associated file to the specified stream using the specified
-     * encoding. If the encoding is <b>null</b>, the default encoding is used.
-     *
-     * @param out the output stream
-     * @param encoding the encoding to be used, {@code null} to use the default
-     *        encoding
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    public void save(final OutputStream out, final String encoding)
-            throws ConfigurationException
-    {
-        saveToStream(out, encoding, null);
-    }
-
-    /**
-     * Saves the associated file to the given {@code Writer}.
-     *
-     * @param out the {@code Writer}
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    public void save(final Writer out) throws ConfigurationException
-    {
-        checkContent();
-        injectNullFileLocator();
-        saveToWriter(out);
-    }
-
-    /**
-     * Prepares a builder for a {@code FileLocator} which does not have a
-     * defined file location. Other properties (e.g. encoding or file system)
-     * are initialized from the {@code FileLocator} associated with this object.
-     *
-     * @return the initialized builder for a {@code FileLocator}
-     */
-    private FileLocatorBuilder prepareNullLocatorBuilder()
-    {
-        return FileLocatorUtils.fileLocator(getFileLocator()).sourceURL(null)
-                .basePath(null).fileName(null);
-    }
-
-    /**
-     * Checks whether the associated {@code FileBased} object implements the
-     * {@code FileLocatorAware} interface. If this is the case, a
-     * {@code FileLocator} instance is injected which returns only <b>null</b>
-     * values. This method is called if no file location is available (e.g. if
-     * data is to be loaded from a stream). The encoding of the injected locator
-     * is derived from this object.
-     */
-    private void injectNullFileLocator()
-    {
-        if (getContent() instanceof FileLocatorAware)
-        {
-            final FileLocator locator = prepareNullLocatorBuilder().create();
-            ((FileLocatorAware) getContent()).initFileLocator(locator);
-        }
-    }
-
-    /**
-     * Injects a {@code FileLocator} pointing to the specified URL if the
-     * current {@code FileBased} object implements the {@code FileLocatorAware}
-     * interface.
-     *
-     * @param url the URL for the locator
-     */
-    private void injectFileLocator(final URL url)
-    {
-        if (url == null)
-        {
-            injectNullFileLocator();
-        }
-        else
-        {
-            if (getContent() instanceof FileLocatorAware)
-            {
-                final FileLocator locator =
-                        prepareNullLocatorBuilder().sourceURL(url).create();
-                ((FileLocatorAware) getContent()).initFileLocator(locator);
-            }
-        }
-    }
-
-    /**
-     * Obtains a {@code SynchronizerSupport} for the current content. If the
-     * content implements this interface, it is returned. Otherwise, result is a
-     * dummy object. This method is called before load and save operations. The
-     * returned object is used for synchronization.
-     *
-     * @return the {@code SynchronizerSupport} for synchronization
-     */
-    private SynchronizerSupport fetchSynchronizerSupport()
-    {
-        if (getContent() instanceof SynchronizerSupport)
-        {
-            return (SynchronizerSupport) getContent();
-        }
-        return DUMMY_SYNC_SUPPORT;
-    }
-
-    /**
-     * Internal helper method for loading the associated file from the location
-     * specified in the given {@code FileLocator}.
-     *
      * @param locator the current {@code FileLocator}
      * @throws ConfigurationException if an error occurs
      */
-    private void load(final FileLocator locator) throws ConfigurationException
+    private void load(final String fileName, final FileLocator locator)
+            throws ConfigurationException
     {
-        final URL url = FileLocatorUtils.locateOrThrow(locator);
+        final FileLocator locFileName = createLocatorWithFileName(fileName, locator);
+        final URL url = FileLocatorUtils.locateOrThrow(locFileName);
         load(url, locator);
     }
 
     /**
+     * Loads the associated file from the specified URL. The location stored in
+     * this object is not changed.
+     *
+     * @param url the URL of the file to be loaded
+     * @throws ConfigurationException if an error occurs
+     */
+    public void load(final URL url) throws ConfigurationException
+    {
+        load(url, checkContentAndGetLocator());
+    }
+
+    /**
      * Internal helper method for loading a file from the given URL.
      *
      * @param url the URL
@@ -1004,31 +889,26 @@
     }
 
     /**
-     * Internal helper method for loading a file from a file name.
+     * Internal helper method for loading a file from the given reader.
      *
-     * @param fileName the file name
-     * @param locator the current {@code FileLocator}
+     * @param in the reader
      * @throws ConfigurationException if an error occurs
      */
-    private void load(final String fileName, final FileLocator locator)
-            throws ConfigurationException
+    private void loadFromReader(final Reader in) throws ConfigurationException
     {
-        final FileLocator locFileName = createLocatorWithFileName(fileName, locator);
-        final URL url = FileLocatorUtils.locateOrThrow(locFileName);
-        load(url, locator);
-    }
-
-    /**
-     * Internal helper method for loading a file from the given input stream.
-     *
-     * @param in the input stream
-     * @param locator the current {@code FileLocator}
-     * @throws ConfigurationException if an error occurs
-     */
-    private void load(final InputStream in, final FileLocator locator)
-            throws ConfigurationException
-    {
-        load(in, locator.getEncoding());
+        fireLoadingEvent();
+        try
+        {
+            getContent().read(in);
+        }
+        catch (final IOException ioex)
+        {
+            throw new ConfigurationException(ioex);
+        }
+        finally
+        {
+            fireLoadedEvent();
+        }
     }
 
     /**
@@ -1120,25 +1000,132 @@
     }
 
     /**
-     * Internal helper method for loading a file from the given reader.
+     * Locates the referenced file if necessary and ensures that the associated
+     * {@link FileLocator} is fully initialized. When accessing the referenced
+     * file the information stored in the associated {@code FileLocator} is
+     * used. If this information is incomplete (e.g. only the file name is set),
+     * an attempt to locate the file may have to be performed on each access. By
+     * calling this method such an attempt is performed once, and the results of
+     * a successful localization are stored. Hence, later access to the
+     * referenced file can be more efficient. Also, all properties pointing to
+     * the referenced file in this object's {@code FileLocator} are set (i.e.
+     * the URL, the base path, and the file name). If the referenced file cannot
+     * be located, result is <b>false</b>. This means that the information in
+     * the current {@code FileLocator} is insufficient or wrong. If the
+     * {@code FileLocator} is already fully defined, it is not changed.
      *
-     * @param in the reader
-     * @throws ConfigurationException if an error occurs
+     * @return a flag whether the referenced file could be located successfully
+     * @see FileLocatorUtils#fullyInitializedLocator(FileLocator)
      */
-    private void loadFromReader(final Reader in) throws ConfigurationException
+    public boolean locate()
     {
-        fireLoadingEvent();
+        boolean result;
+        boolean done;
+
+        do
+        {
+            final FileLocator locator = getFileLocator();
+            FileLocator fullLocator =
+                    FileLocatorUtils.fullyInitializedLocator(locator);
+            if (fullLocator == null)
+            {
+                result = false;
+                fullLocator = locator;
+            }
+            else
+            {
+                result =
+                        fullLocator != locator
+                                || FileLocatorUtils.isFullyInitialized(locator);
+            }
+            done = fileLocator.compareAndSet(locator, fullLocator);
+        } while (!done);
+
+        return result;
+    }
+
+    /**
+     * Prepares a builder for a {@code FileLocator} which does not have a
+     * defined file location. Other properties (e.g. encoding or file system)
+     * are initialized from the {@code FileLocator} associated with this object.
+     *
+     * @return the initialized builder for a {@code FileLocator}
+     */
+    private FileLocatorBuilder prepareNullLocatorBuilder()
+    {
+        return FileLocatorUtils.fileLocator(getFileLocator()).sourceURL(null)
+                .basePath(null).fileName(null);
+    }
+
+    /**
+     * Removes the specified listener from this object.
+     *
+     * @param l the listener to be removed
+     */
+    public void removeFileHandlerListener(final FileHandlerListener l)
+    {
+        listeners.remove(l);
+    }
+
+    /**
+     * Resets the {@code FileSystem} used by this object. It is set to the
+     * default file system.
+     */
+    public void resetFileSystem()
+    {
+        setFileSystem(null);
+    }
+
+    /**
+     * Saves the associated file to the current location set for this object.
+     * Before this method can be called a valid location must have been set.
+     *
+     * @throws ConfigurationException if an error occurs or no location has been
+     *         set yet
+     */
+    public void save() throws ConfigurationException
+    {
+        save(checkContentAndGetLocator());
+    }
+
+    /**
+     * Saves the associated file to the specified {@code File}. The file is
+     * created automatically if it doesn't exist. This does not change the
+     * location of this object (use {@link #setFile} if you need it).
+     *
+     * @param file the target file
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    public void save(final File file) throws ConfigurationException
+    {
+        save(file, checkContentAndGetLocator());
+    }
+
+    /**
+     * Internal helper method for saving data to the given {@code File}.
+     *
+     * @param file the target file
+     * @param locator the current {@code FileLocator}
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    private void save(final File file, final FileLocator locator) throws ConfigurationException
+    {
+        OutputStream out = null;
+
         try
         {
-            getContent().read(in);
+            out = FileLocatorUtils.obtainFileSystem(locator).getOutputStream(file);
+            saveToStream(out, locator.getEncoding(), file.toURI().toURL());
         }
-        catch (final IOException ioex)
+        catch (final MalformedURLException muex)
         {
-            throw new ConfigurationException(ioex);
+            throw new ConfigurationException(muex);
         }
         finally
         {
-            fireLoadedEvent();
+            closeSilent(out);
         }
     }
 
@@ -1168,6 +1155,63 @@
     }
 
     /**
+     * Saves the associated file to the specified stream using the encoding
+     * returned by {@link #getEncoding()}.
+     *
+     * @param out the output stream
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    public void save(final OutputStream out) throws ConfigurationException
+    {
+        save(out, checkContentAndGetLocator());
+    }
+
+    /**
+     * Internal helper method for saving a file to the given output stream.
+     *
+     * @param out the output stream
+     * @param locator the current {@code FileLocator}
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    private void save(final OutputStream out, final FileLocator locator)
+            throws ConfigurationException
+    {
+        save(out, locator.getEncoding());
+    }
+
+    /**
+     * Saves the associated file to the specified stream using the specified
+     * encoding. If the encoding is <b>null</b>, the default encoding is used.
+     *
+     * @param out the output stream
+     * @param encoding the encoding to be used, {@code null} to use the default
+     *        encoding
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    public void save(final OutputStream out, final String encoding)
+            throws ConfigurationException
+    {
+        saveToStream(out, encoding, null);
+    }
+
+    /**
+     * Saves the associated file to the specified file name. This does not
+     * change the location of this object (use {@link #setFileName(String)} if
+     * you need it).
+     *
+     * @param fileName the file name
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    public void save(final String fileName) throws ConfigurationException
+    {
+        save(fileName, checkContentAndGetLocator());
+    }
+
+    /**
      * Internal helper method for saving data to the given file name.
      *
      * @param fileName the path to the target file
@@ -1198,6 +1242,19 @@
     }
 
     /**
+     * Saves the associated file to the specified URL. This does not change the
+     * location of this object (use {@link #setURL(URL)} if you need it).
+     *
+     * @param url the URL
+     * @throws ConfigurationException if an error occurs during the save
+     *         operation
+     */
+    public void save(final URL url) throws ConfigurationException
+    {
+        save(url, checkContentAndGetLocator());
+    }
+
+    /**
      * Internal helper method for saving data to the given URL.
      *
      * @param url the target URL
@@ -1231,44 +1288,17 @@
     }
 
     /**
-     * Internal helper method for saving data to the given {@code File}.
+     * Saves the associated file to the given {@code Writer}.
      *
-     * @param file the target file
-     * @param locator the current {@code FileLocator}
+     * @param out the {@code Writer}
      * @throws ConfigurationException if an error occurs during the save
      *         operation
      */
-    private void save(final File file, final FileLocator locator) throws ConfigurationException
+    public void save(final Writer out) throws ConfigurationException
     {
-        OutputStream out = null;
-
-        try
-        {
-            out = FileLocatorUtils.obtainFileSystem(locator).getOutputStream(file);
-            saveToStream(out, locator.getEncoding(), file.toURI().toURL());
-        }
-        catch (final MalformedURLException muex)
-        {
-            throw new ConfigurationException(muex);
-        }
-        finally
-        {
-            closeSilent(out);
-        }
-    }
-
-    /**
-     * Internal helper method for saving a file to the given output stream.
-     *
-     * @param out the output stream
-     * @param locator the current {@code FileLocator}
-     * @throws ConfigurationException if an error occurs during the save
-     *         operation
-     */
-    private void save(final OutputStream out, final FileLocator locator)
-            throws ConfigurationException
-    {
-        save(out, locator.getEncoding());
+        checkContent();
+        injectNullFileLocator();
+        saveToWriter(out);
     }
 
     /**
@@ -1341,233 +1371,203 @@
     }
 
     /**
-     * Creates a {@code FileLocator} which is a copy of the passed in one, but
-     * has the given file name set to reference the target file.
+     * Sets the base path. The base path is typically either a path to a
+     * directory or a URL. Together with the value passed to the
+     * {@code setFileName()} method it defines the location of the configuration
+     * file to be loaded. The strategies for locating the file are quite
+     * tolerant. For instance if the file name is already an absolute path or a
+     * fully defined URL, the base path will be ignored. The base path can also
+     * be a URL, in which case the file name is interpreted in this URL's
+     * context. If other methods are used for determining the location of the
+     * associated file (e.g. {@code setFile()} or {@code setURL()}), the base
+     * path is automatically set. Setting the base path using this method
+     * automatically sets the URL to <b>null</b> because it has to be
+     * determined anew based on the file name and the base path.
      *
-     * @param fileName the file name
-     * @param locator the {@code FileLocator} to copy
-     * @return the manipulated {@code FileLocator} with the file name
+     * @param basePath the base path.
      */
-    private FileLocator createLocatorWithFileName(final String fileName,
-            final FileLocator locator)
+    public void setBasePath(final String basePath)
     {
-        return FileLocatorUtils.fileLocator(locator).sourceURL(null)
-                .fileName(fileName).create();
-    }
-
-    /**
-     * Checks whether a content object is available. If not, an exception is
-     * thrown. This method is called whenever the content object is accessed.
-     *
-     * @throws ConfigurationException if not content object is defined
-     */
-    private void checkContent() throws ConfigurationException
-    {
-        if (getContent() == null)
+        final String path = normalizeFileURL(basePath);
+        new Updater()
         {
-            throw new ConfigurationException("No content available!");
-        }
-    }
-
-    /**
-     * Checks whether a content object is available and returns the current
-     * {@code FileLocator}. If there is no content object, an exception is
-     * thrown. This is a typical operation to be performed before a load() or
-     * save() operation.
-     *
-     * @return the current {@code FileLocator} to be used for the calling
-     *         operation
-     */
-    private FileLocator checkContentAndGetLocator()
-            throws ConfigurationException
-    {
-        checkContent();
-        return getFileLocator();
-    }
-
-    /**
-     * Notifies the registered listeners about the start of a load operation.
-     */
-    private void fireLoadingEvent()
-    {
-        for (final FileHandlerListener l : listeners)
-        {
-            l.loading(this);
-        }
-    }
-
-    /**
-     * Notifies the registered listeners about a completed load operation.
-     */
-    private void fireLoadedEvent()
-    {
-        for (final FileHandlerListener l : listeners)
-        {
-            l.loaded(this);
-        }
-    }
-
-    /**
-     * Notifies the registered listeners about the start of a save operation.
-     */
-    private void fireSavingEvent()
-    {
-        for (final FileHandlerListener l : listeners)
-        {
-            l.saving(this);
-        }
-    }
-
-    /**
-     * Notifies the registered listeners about a completed save operation.
-     */
-    private void fireSavedEvent()
-    {
-        for (final FileHandlerListener l : listeners)
-        {
-            l.saved(this);
-        }
-    }
-
-    /**
-     * Notifies the registered listeners about a property update.
-     */
-    private void fireLocationChangedEvent()
-    {
-        for (final FileHandlerListener l : listeners)
-        {
-            l.locationChanged(this);
-        }
-    }
-
-    /**
-     * Normalizes URLs to files. Ensures that file URLs start with the correct
-     * protocol.
-     *
-     * @param fileName the string to be normalized
-     * @return the normalized file URL
-     */
-    private static String normalizeFileURL(String fileName)
-    {
-        if (fileName != null && fileName.startsWith(FILE_SCHEME)
-                && !fileName.startsWith(FILE_SCHEME_SLASH))
-        {
-            fileName =
-                    FILE_SCHEME_SLASH
-                            + fileName.substring(FILE_SCHEME.length());
-        }
-        return fileName;
-    }
-
-    /**
-     * A helper method for closing a stream. Occurring exceptions will be
-     * ignored.
-     *
-     * @param cl the stream to be closed (may be <b>null</b>)
-     */
-    private static void closeSilent(final Closeable cl)
-    {
-        try
-        {
-            if (cl != null)
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
             {
-                cl.close();
+                builder.basePath(path);
+                builder.sourceURL(null);
             }
         }
-        catch (final IOException e)
-        {
-            LogFactory.getLog(FileHandler.class).warn("Exception when closing " + cl, e);
-        }
+        .update();
     }
 
     /**
-     * Creates a {@code File} object from the content of the given
-     * {@code FileLocator} object. If the locator is not defined, result is
-     * <b>null</b>.
+     * Sets the encoding of the associated file. The encoding applies if binary
+     * files are loaded. Note that in this case setting an encoding is
+     * recommended; otherwise the platform's default encoding is used.
      *
-     * @param loc the {@code FileLocator}
-     * @return a {@code File} object pointing to the associated file
+     * @param encoding the encoding of the associated file
      */
-    private static File createFile(final FileLocator loc)
+    public void setEncoding(final String encoding)
     {
-        if (loc.getFileName() == null && loc.getSourceURL() == null)
+        new Updater()
         {
-            return null;
-        }
-        else if (loc.getSourceURL() != null)
-        {
-            return FileLocatorUtils.fileFromURL(loc.getSourceURL());
-        }
-        else
-        {
-            return FileLocatorUtils.getFile(loc.getBasePath(),
-                    loc.getFileName());
-        }
-    }
-
-    /**
-     * Creates an uninitialized file locator.
-     *
-     * @return the locator
-     */
-    private static FileLocator emptyFileLocator()
-    {
-        return FileLocatorUtils.fileLocator().create();
-    }
-
-    /**
-     * Helper method for checking a file handler which is to be copied. Throws
-     * an exception if the handler is <b>null</b>.
-     *
-     * @param c the {@code FileHandler} from which to copy the location
-     * @return the same {@code FileHandler}
-     */
-    private static FileHandler checkSourceHandler(final FileHandler c)
-    {
-        if (c == null)
-        {
-            throw new IllegalArgumentException(
-                    "FileHandler to assign must not be null!");
-        }
-        return c;
-    }
-
-    /**
-     * An internal class that performs all update operations of the handler's
-     * {@code FileLocator} in a safe way even if there is concurrent access.
-     * This class implements anon-blocking algorithm for replacing the immutable
-     * {@code FileLocator} instance stored in an atomic reference by a
-     * manipulated instance. (If we already had lambdas, this could be done
-     * without a class in a more elegant way.)
-     */
-    private abstract class Updater
-    {
-        /**
-         * Performs an update of the enclosing file handler's
-         * {@code FileLocator} object.
-         */
-        public void update()
-        {
-            boolean done;
-            do
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
             {
-                final FileLocator oldLocator = fileLocator.get();
-                final FileLocatorBuilder builder =
-                        FileLocatorUtils.fileLocator(oldLocator);
-                updateBuilder(builder);
-                done = fileLocator.compareAndSet(oldLocator, builder.create());
-            } while (!done);
-            fireLocationChangedEvent();
+                builder.encoding(encoding);
+            }
+        }
+        .update();
+    }
+
+    /**
+     * Sets the location of the associated file as a {@code File} object. The
+     * passed in {@code File} is made absolute if it is not yet. Then the file's
+     * path component becomes the base path and its name component becomes the
+     * file name.
+     *
+     * @param file the location of the associated file
+     */
+    public void setFile(final File file)
+    {
+        final String fileName = file.getName();
+        final String basePath =
+                file.getParentFile() != null ? file.getParentFile()
+                        .getAbsolutePath() : null;
+        new Updater()
+        {
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
+            {
+                builder.fileName(fileName).basePath(basePath).sourceURL(null);
+            }
+        }
+        .update();
+    }
+
+    /**
+     * Sets the file to be accessed by this {@code FileHandler} as a
+     * {@code FileLocator} object.
+     *
+     * @param locator the {@code FileLocator} with the definition of the file to
+     *        be accessed (must not be <b>null</b>
+     * @throws IllegalArgumentException if the {@code FileLocator} is
+     *         <b>null</b>
+     */
+    public void setFileLocator(final FileLocator locator)
+    {
+        if (locator == null)
+        {
+            throw new IllegalArgumentException("FileLocator must not be null!");
         }
 
-        /**
-         * Updates the passed in builder object to apply the manipulation to be
-         * performed by this {@code Updater}. The builder has been setup with
-         * the former content of the {@code FileLocator} to be manipulated.
-         *
-         * @param builder the builder for creating an updated
-         *        {@code FileLocator}
-         */
-        protected abstract void updateBuilder(FileLocatorBuilder builder);
+        fileLocator.set(locator);
+        fireLocationChangedEvent();
+    }
+
+    /**
+     * Set the name of the file. The passed in file name can contain a relative
+     * path. It must be used when referring files with relative paths from
+     * classpath. Use {@code setPath()} to set a full qualified file name. The
+     * URL is set to <b>null</b> as it has to be determined anew based on the
+     * file name and the base path.
+     *
+     * @param fileName the name of the file
+     */
+    public void setFileName(final String fileName)
+    {
+        final String name = normalizeFileURL(fileName);
+        new Updater()
+        {
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
+            {
+                builder.fileName(name);
+                builder.sourceURL(null);
+            }
+        }
+        .update();
+    }
+
+    /**
+     * Sets the {@code FileSystem} to be used by this object when locating
+     * files. If a <b>null</b> value is passed in, the file system is reset to
+     * the default file system.
+     *
+     * @param fileSystem the {@code FileSystem}
+     */
+    public void setFileSystem(final FileSystem fileSystem)
+    {
+        new Updater()
+        {
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
+            {
+                builder.fileSystem(fileSystem);
+            }
+        }
+        .update();
+    }
+
+    /**
+     * Sets the {@code FileLocationStrategy} to be applied when accessing the
+     * associated file. The strategy is stored in the underlying
+     * {@link FileLocator}. The argument can be <b>null</b>; this causes the
+     * default {@code FileLocationStrategy} to be used.
+     *
+     * @param strategy the {@code FileLocationStrategy}
+     * @see FileLocatorUtils#DEFAULT_LOCATION_STRATEGY
+     */
+    public void setLocationStrategy(final FileLocationStrategy strategy)
+    {
+        new Updater()
+        {
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
+            {
+                builder.locationStrategy(strategy);
+            }
+
+        }
+        .update();
+    }
+
+    /**
+     * Sets the location of the associated file as a full or relative path name.
+     * The passed in path should represent a valid file name on the file system.
+     * It must not be used to specify relative paths for files that exist in
+     * classpath, either plain file system or compressed archive, because this
+     * method expands any relative path to an absolute one which may end in an
+     * invalid absolute path for classpath references.
+     *
+     * @param path the full path name of the associated file
+     */
+    public void setPath(final String path)
+    {
+        setFile(new File(path));
+    }
+
+    /**
+     * Sets the location of the associated file as a URL. For loading this can
+     * be an arbitrary URL with a supported protocol. If the file is to be
+     * saved, too, a URL with the &quot;file&quot; protocol should be provided.
+     * This method sets the file name and the base path to <b>null</b>.
+     * They have to be determined anew based on the new URL.
+     *
+     * @param url the location of the file as URL
+     */
+    public void setURL(final URL url)
+    {
+        new Updater()
+        {
+            @Override
+            protected void updateBuilder(final FileLocatorBuilder builder)
+            {
+                builder.sourceURL(url);
+                builder.basePath(null).fileName(null);
+            }
+        }
+        .update();
     }
 }