1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.opensaml.util.resource;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import java.util.TimerTask;
22
23 import org.joda.time.DateTime;
24 import org.opensaml.util.resource.ResourceChangeListener.ResourceChange;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28
29
30
31 public class ResourceChangeWatcher extends TimerTask {
32
33
34 public static final long DEFAULT_POLL_FREQUENCY = 1000 * 60 * 60 * 12;
35
36
37 public static final int DEFAULT_MAX_RETRY_ATTEMPTS = 0;
38
39
40 private final Logger log = LoggerFactory.getLogger(ResourceChangeWatcher.class);
41
42
43 private Resource watchedResource;
44
45
46 private long pollFrequency;
47
48
49 private int maxRetryAttempts;
50
51
52 private int currentRetryAttempts;
53
54
55 private boolean resourceExist;
56
57
58 private DateTime lastModification;
59
60
61 private List<ResourceChangeListener> resourceListeners;
62
63
64
65
66
67
68
69
70 public ResourceChangeWatcher(Resource resource) throws ResourceException {
71 this(resource, DEFAULT_POLL_FREQUENCY, DEFAULT_MAX_RETRY_ATTEMPTS);
72 }
73
74
75
76
77
78
79
80
81
82 public ResourceChangeWatcher(Resource resource, long pollingFrequency) throws ResourceException {
83 this(resource, pollingFrequency, DEFAULT_MAX_RETRY_ATTEMPTS);
84 }
85
86
87
88
89
90
91
92
93
94
95 public ResourceChangeWatcher(Resource resource, long pollingFrequency, int retryAttempts) throws ResourceException {
96 if (resource == null) {
97 throw new NullPointerException("Watched resource is null");
98 }
99
100 if (pollingFrequency <= 0) {
101 throw new IllegalArgumentException("Polling frequency must be greater than zero");
102 }
103
104 if (retryAttempts < 0) {
105 throw new IllegalArgumentException("Max retry attempts must be greater than, or equal to, zero");
106 }
107
108 watchedResource = resource;
109 pollFrequency = pollingFrequency;
110 maxRetryAttempts = retryAttempts;
111 currentRetryAttempts = 0;
112
113 if (watchedResource.exists()) {
114 resourceExist = true;
115 lastModification = watchedResource.getLastModifiedTime();
116 } else {
117 resourceExist = false;
118 }
119
120 resourceListeners = new ArrayList<ResourceChangeListener>(5);
121 log.debug("Watching resource: " + watchedResource.getLocation()
122 + ", polling frequency: {}ms, max retry attempts: {}", pollFrequency, maxRetryAttempts);
123 }
124
125
126
127
128
129
130 public long getPollingFrequency() {
131 return pollFrequency;
132 }
133
134
135
136
137
138
139
140 public List<ResourceChangeListener> getResourceListeners() {
141 return resourceListeners;
142 }
143
144
145 public void run() {
146 try {
147 log.trace("Checking resource for changes: {}", watchedResource.getLocation());
148 if (watchedResource.exists()) {
149 if (!resourceExist) {
150 resourceExist = true;
151 signalListeners(ResourceChange.CREATION);
152 lastModification = watchedResource.getLastModifiedTime();
153 } else {
154 if (lastModification.isBefore(watchedResource.getLastModifiedTime())) {
155 signalListeners(ResourceChange.UPDATE);
156 lastModification = watchedResource.getLastModifiedTime();
157 }
158 }
159 } else {
160 if (resourceExist) {
161 resourceExist = false;
162 signalListeners(ResourceChange.DELETE);
163 }
164 }
165 currentRetryAttempts = 0;
166 } catch (ResourceException e) {
167 log.warn("Resource " + watchedResource.getLocation() + " could not be accessed", e);
168 currentRetryAttempts++;
169 if (currentRetryAttempts >= maxRetryAttempts) {
170 cancel();
171 log.error("Resource " + watchedResource.getLocation()
172 + " was not accessible for max number of retry attempts. This resource will no longer be watched");
173 }
174 }
175 }
176
177
178
179
180
181
182 protected void signalListeners(ResourceChange changeType) {
183 synchronized (resourceListeners) {
184 switch (changeType) {
185 case CREATION:
186 log.debug("Publishing creation event for resource: {}", watchedResource.getLocation());
187 for (ResourceChangeListener listener : resourceListeners) {
188 listener.onResourceCreate(watchedResource);
189 }
190 break;
191 case UPDATE:
192 log.debug("Publishing update event for resource: {}", watchedResource.getLocation());
193 for (ResourceChangeListener listener : resourceListeners) {
194 listener.onResourceUpdate(watchedResource);
195 }
196 break;
197 case DELETE:
198 log.debug("Publishing delete event for resource: {}", watchedResource.getLocation());
199 for (ResourceChangeListener listener : resourceListeners) {
200 listener.onResourceDelete(watchedResource);
201 }
202 break;
203 default:
204 break;
205 }
206 }
207 }
208 }