    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     */
    017
    018    package org.apache.commons.jci.listeners;
    019
    020    import java.io.File;
    021    import java.io.FileInputStream;
    022    import java.util.Collection;
    023    import java.util.HashSet;
    024    import java.util.Set;
    025
    026    import org.apache.commons.io.IOUtils;
    027    import org.apache.commons.jci.ReloadingClassLoader;
    028    import org.apache.commons.jci.monitor.FilesystemAlterationObserver;
    029    import org.apache.commons.jci.stores.MemoryResourceStore;
    030    import org.apache.commons.jci.stores.ResourceStore;
    031    import org.apache.commons.jci.stores.Transactional;
    032    import org.apache.commons.jci.utils.ConversionUtils;
    033    import org.apache.commons.logging.Log;
    034    import org.apache.commons.logging.LogFactory;
    035
    036    /**
    037     * This Listener waits for FAM events to trigger a reload of classes
    038     * or resources.
    039     *
    040     * @author tcurdt
    041     */
    042    public class ReloadingListener extends AbstractFilesystemAlterationListener {
    043
    044        private final Log log = LogFactory.getLog(ReloadingListener.class);
    045
    046        private final Set<ReloadNotificationListener> notificationListeners = new HashSet<ReloadNotificationListener>();
    047        private final ResourceStore store;
    048
    049        public ReloadingListener() {
    050            this(new MemoryResourceStore());
    051        }
    052
    053        public ReloadingListener( final ResourceStore pStore ) {
    054            store = pStore;
    055        }
    056
    057        public ResourceStore getStore() {
    058            return store;
    059        }
    060
    061        public void addReloadNotificationListener( final ReloadNotificationListener pNotificationListener ) {
    062            notificationListeners.add(pNotificationListener);
    063
    064            if (pNotificationListener instanceof ReloadingClassLoader) {
    065                ((ReloadingClassLoader)pNotificationListener).addResourceStore(store);
    066            }
    067
    068        }
    069
    070        public boolean isReloadRequired( final FilesystemAlterationObserver pObserver ) {
    071            boolean reload = false;
    072
    073            final Collection<File> created = getCreatedFiles();
    074            final Collection<File> changed = getChangedFiles();
    075            final Collection<File> deleted = getDeletedFiles();
    076
    077            log.debug("created:" + created.size() + " changed:" + changed.size() + " deleted:" + deleted.size() + " resources");
    078
    079            if (deleted.size() > 0) {
    080                for (File file : deleted) {
    081                    final String resourceName = ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), file));
    082                    store.remove(resourceName);
    083                }
    084                reload = true;
    085            }
    086
    087            if (created.size() > 0) {
    088                for (File file : created) {
    089                    FileInputStream is = null;
    090                    try {
    091                        is = new FileInputStream(file);
    092                        final byte[] bytes = IOUtils.toByteArray(is);
    093                        final String resourceName = ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), file));
    094                        store.write(resourceName, bytes);
    095                    } catch(final Exception e) {
    096                        log.error("could not load " + file, e);
    097                    } finally {
    098                        IOUtils.closeQuietly(is);
    099                    }
    100                }
    101            }
    102
    103            if (changed.size() > 0) {
    104                for (File file : changed) {
    105                    FileInputStream is = null;
    106                    try {
    107                        is = new FileInputStream(file);
    108                        final byte[] bytes = IOUtils.toByteArray(is);
    109                        final String resourceName = ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), file));
    110                        store.write(resourceName, bytes);
    111                    } catch(final Exception e) {
    112                        log.error("could not load " + file, e);
    113                    } finally {
    114                        IOUtils.closeQuietly(is);
    115                    }
    116                }
    117                reload = true;
    118            }
    119
    120            return reload;
    121        }
    122
    123        @Override
    124        public void onStop( final FilesystemAlterationObserver pObserver ) {
    125
    126
    127            if (store instanceof Transactional) {
    128                ((Transactional)store).onStart();
    129            }
    130
    131            final boolean reload = isReloadRequired(pObserver);
    132
    133            if (store instanceof Transactional) {
    134                ((Transactional)store).onStop();
    135            }
    136
    137            if (reload) {
    138                notifyReloadNotificationListeners();
    139            }
    140
    141            super.onStop(pObserver);
    142        }
    143
    144        void notifyReloadNotificationListeners() {
    145            for (ReloadNotificationListener listener : notificationListeners) {
    146                log.debug("notifying listener " + listener);
    147
    148                listener.handleNotification();
    149            }
    150        }
    151
    152        @Override
    153        public void onDirectoryCreate( final File pDir ) {
    154        }
    155        @Override
    156        public void onDirectoryChange( final File pDir ) {
    157        }
    158        @Override
    159        public void onDirectoryDelete( final File pDir ) {
    160        }
    161    }