View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jci.listeners;
19  
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.util.Collection;
23  import java.util.HashSet;
24  import java.util.Set;
25  
26  import org.apache.commons.io.IOUtils;
27  import org.apache.commons.jci.ReloadingClassLoader;
28  import org.apache.commons.jci.monitor.FilesystemAlterationObserver;
29  import org.apache.commons.jci.stores.MemoryResourceStore;
30  import org.apache.commons.jci.stores.ResourceStore;
31  import org.apache.commons.jci.stores.Transactional;
32  import org.apache.commons.jci.utils.ConversionUtils;
33  import org.apache.commons.logging.Log;
34  import org.apache.commons.logging.LogFactory;
35  
36  /**
37   * This Listener waits for FAM events to trigger a reload of classes
38   * or resources.
39   * 
40   * @author tcurdt
41   */
42  public class ReloadingListener extends AbstractFilesystemAlterationListener {
43  
44      private final Log log = LogFactory.getLog(ReloadingListener.class);
45      
46      private final Set<ReloadNotificationListener> notificationListeners = new HashSet<ReloadNotificationListener>();
47      private final ResourceStore store;
48      
49      public ReloadingListener() {
50          this(new MemoryResourceStore());
51      }
52  
53      public ReloadingListener( final ResourceStore pStore ) {
54          store = pStore;
55      }
56  
57      public ResourceStore getStore() {
58          return store;
59      }
60  
61      public void addReloadNotificationListener( final ReloadNotificationListener pNotificationListener ) {
62          notificationListeners.add(pNotificationListener);
63  
64          if (pNotificationListener instanceof ReloadingClassLoader) {
65              ((ReloadingClassLoader)pNotificationListener).addResourceStore(store);
66          }
67  
68      }
69      
70      public boolean isReloadRequired( final FilesystemAlterationObserver pObserver ) {
71          boolean reload = false;
72  
73          final Collection<File> created = getCreatedFiles();
74          final Collection<File> changed = getChangedFiles();
75          final Collection<File> deleted = getDeletedFiles();
76          
77          log.debug("created:" + created.size() + " changed:" + changed.size() + " deleted:" + deleted.size() + " resources");
78  
79          if (deleted.size() > 0) {
80              for (File file : deleted) {
81                  final String resourceName = ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), file));
82                  store.remove(resourceName);
83              }
84              reload = true;
85          }
86  
87          if (created.size() > 0) {
88              for (File file : created) {
89                  FileInputStream is = null;
90                  try {
91                      is = new FileInputStream(file);
92                      final byte[] bytes = IOUtils.toByteArray(is);
93                      final String resourceName = ConversionUtils.getResourceNameFromFileName(ConversionUtils.relative(pObserver.getRootDirectory(), file));
94                      store.write(resourceName, bytes);
95                  } catch(final Exception e) {
96                      log.error("could not load " + file, e);
97                  } finally {
98                      IOUtils.closeQuietly(is);
99                  }
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 }