001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.util;
018
019import java.lang.ref.WeakReference;
020
021import org.apache.commons.vfs2.FileChangeEvent;
022import org.apache.commons.vfs2.FileListener;
023import org.apache.commons.vfs2.FileName;
024import org.apache.commons.vfs2.FileObject;
025import org.apache.commons.vfs2.FileSystem;
026
027/**
028 * Wraps a listener with a WeakReference.
029 *
030 * @since 2.0
031 */
032public class WeakRefFileListener implements FileListener {
033
034    /**
035     * Install the {@code listener} at the given {@code file}.
036     * <p>
037     * This installs a wrapper with a weak reference, so the listener can
038     * be collected. The reference to the listener is removed when the
039     * first event can't be delivered.
040     * <p>
041     * Warning: you cannot remove the listener with
042     * {@code fs.removeListener(file, listener)} as you do'nt have the wrapper
043     * instance at hand.
044     * <p>
045     * Method is used by {@link org.apache.commons.vfs2.provider.DelegateFileObject},
046     * as used for {@link org.apache.commons.vfs2.impl.VirtualFileSystem}.
047     *
048     * @param file The FileObject to listen on.
049     * @param listener The FileListener
050     */
051    public static void installListener(final FileObject file, final FileListener listener) {
052        file.getFileSystem().addListener(file, new WeakRefFileListener(file, listener));
053    }
054
055    private final FileSystem fs;
056    private final FileName name;
057
058    private final WeakReference<FileListener> listener;
059
060    /**
061     * Constructs a new instance.
062     *
063     * @param file the file object.
064     * @param listener the file listener.
065     */
066    protected WeakRefFileListener(final FileObject file, final FileListener listener) {
067        fs = file.getFileSystem();
068        name = file.getName();
069        this.listener = new WeakReference<>(listener);
070    }
071
072    /**
073     * Called when a file is changed.
074     * <p>
075     * This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}.
076     * </p>
077     *
078     * @param event The FileChangeEvent.
079     * @throws Exception if an error occurs.
080     */
081    @Override
082    public void fileChanged(final FileChangeEvent event) throws Exception {
083        final FileListener listener = getListener();
084        if (listener != null) {
085            listener.fileChanged(event);
086        }
087    }
088
089    /**
090     * Called when a file is created.
091     *
092     * @param event The FileChangeEvent.
093     * @throws Exception if an error occurs.
094     */
095    @Override
096    public void fileCreated(final FileChangeEvent event) throws Exception {
097        final FileListener listener = getListener();
098        if (listener != null) {
099            listener.fileCreated(event);
100        }
101    }
102
103    /**
104     * Called when a file is deleted.
105     *
106     * @param event The FileChangeEvent.
107     * @throws Exception if an error occurs.
108     */
109    @Override
110    public void fileDeleted(final FileChangeEvent event) throws Exception {
111        final FileListener listener = getListener();
112        if (listener != null) {
113            listener.fileDeleted(event);
114        }
115    }
116
117    /**
118     * Gets the wrapped listener. If it is gone, the WeakRefFileListener wrapper will remove itself from the list of
119     * listeners.
120     *
121     * @return The FileListener.
122     * @throws Exception if an error occurs.
123     */
124    protected FileListener getListener() throws Exception {
125        final FileListener listener = this.listener.get();
126        if (listener == null) {
127            try (FileObject fileObject = fs.resolveFile(name)) {
128                fileObject.getFileSystem().removeListener(fileObject, this);
129            }
130        }
131        return listener;
132    }
133}