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 }