KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > lenya > ac > file > FileItemManager


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17
18 /* $Id: FileItemManager.java 43237 2004-08-16 15:59:51Z andreas $ */
19
20 package org.apache.lenya.ac.file;
21
22 import java.io.File JavaDoc;
23 import java.io.FileFilter JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.HashMap JavaDoc;
27 import java.util.HashSet JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
32
33 import org.apache.avalon.framework.configuration.Configuration;
34 import org.apache.avalon.framework.configuration.ConfigurationException;
35 import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
36 import org.apache.lenya.ac.AccessControlException;
37 import org.apache.lenya.ac.Group;
38 import org.apache.lenya.ac.Groupable;
39 import org.apache.lenya.ac.Item;
40 import org.apache.lenya.ac.ItemManagerListener;
41 import org.apache.lenya.ac.impl.ItemConfiguration;
42 import org.apache.log4j.Category;
43
44 /**
45  * Abstract superclass for classes that manage items loaded from configuration files.
46  */

47 public abstract class FileItemManager {
48     private static final Category log = Category.getInstance(FileItemManager.class);
49
50     public static final String JavaDoc PATH = "config" + File.separator + "ac" + File.separator + "passwd";
51     
52     private Map JavaDoc items = new HashMap JavaDoc();
53     private File JavaDoc configurationDirectory;
54     private DirectoryChangeNotifier notifier;
55
56     /**
57      * Create a new ItemManager
58      *
59      * @param configurationDirectory where the items are fetched from
60      * @throws AccessControlException if the item manager cannot be instantiated
61      */

62     protected FileItemManager(File JavaDoc configurationDirectory) throws AccessControlException {
63         assert configurationDirectory != null;
64
65         if (!configurationDirectory.exists() || !configurationDirectory.isDirectory()) {
66             throw new AccessControlException(
67                 "The directory [" + configurationDirectory.getAbsolutePath() + "] does not exist!");
68         }
69
70         this.configurationDirectory = configurationDirectory;
71         notifier = new DirectoryChangeNotifier(configurationDirectory, getFileFilter());
72         loadItems();
73     }
74
75     /**
76      * Reloads the items if an item was changed / added / removed.
77      * @throws AccessControlException when something went wrong.
78      */

79     protected void loadItems() throws AccessControlException {
80
81         boolean changed;
82         try {
83             changed = notifier.hasChanged();
84         } catch (IOException JavaDoc e) {
85             throw new AccessControlException(e);
86         }
87
88         if (changed) {
89
90             if (log.isDebugEnabled()) {
91                 log.debug("Item configuration has changed - reloading.");
92             }
93
94             File JavaDoc[] addedFiles = notifier.getAddedFiles();
95
96             for (int i = 0; i < addedFiles.length; i++) {
97                 Item item = loadItem(addedFiles[i]);
98                 add(item);
99             }
100
101             File JavaDoc[] removedFiles = notifier.getRemovedFiles();
102             for (int i = 0; i < removedFiles.length; i++) {
103                 String JavaDoc fileName = removedFiles[i].getName();
104                 String JavaDoc id = fileName.substring(0, fileName.length() - getSuffix().length());
105
106                 Item item = (Item) items.get(id);
107
108                 if (item != null) {
109
110                     if (item instanceof Groupable) {
111                         ((Groupable) item).removeFromAllGroups();
112                     }
113                     if (item instanceof Group) {
114                         ((Group) item).removeAllMembers();
115                     }
116
117                     remove(item);
118                 }
119             }
120
121             File JavaDoc[] changedFiles = notifier.getChangedFiles();
122             for (int i = 0; i < changedFiles.length; i++) {
123                 Item item = loadItem(changedFiles[i]);
124                 update(item);
125             }
126
127         }
128
129     }
130
131     /**
132      * Loads an item from a file.
133      * @param file The file.
134      * @return An item.
135      * @throws AccessControlException when something went wrong.
136      */

137     protected Item loadItem(File JavaDoc file) throws AccessControlException {
138         Configuration config = getItemConfiguration(file);
139
140         String JavaDoc fileName = file.getName();
141         String JavaDoc id = fileName.substring(0, fileName.length() - getSuffix().length());
142         Item item = (Item) items.get(id);
143
144         String JavaDoc klass = getItemClass(config);
145         if (item == null) {
146             try {
147                 item = (Item) Class.forName(klass).newInstance();
148             } catch (Exception JavaDoc e) {
149                 String JavaDoc errorMsg =
150                     "Exception when trying to instanciate: "
151                         + klass
152                         + " with exception: "
153                         + e.fillInStackTrace();
154
155                 // an exception occured when trying to instanciate
156
// a user.
157
log.error(errorMsg);
158                 throw new AccessControlException(errorMsg, e);
159             }
160             item.setConfigurationDirectory(configurationDirectory);
161         }
162
163         try {
164             item.configure(config);
165         } catch (ConfigurationException e) {
166             String JavaDoc errorMsg = "Exception when trying to configure: " + klass;
167             throw new AccessControlException(errorMsg, e);
168         }
169         return item;
170     }
171
172     /**
173      * Returns the class name of an item.
174      * @param config The item configuration.
175      * @return The class name.
176      * @throws AccessControlException when something went wrong.
177      */

178     protected String JavaDoc getItemClass(Configuration config) throws AccessControlException {
179         String JavaDoc klass = null;
180
181         try {
182             klass = config.getAttribute(ItemConfiguration.CLASS_ATTRIBUTE);
183         } catch (ConfigurationException e) {
184             String JavaDoc errorMsg =
185                 "Exception when extracting class name from identity file: "
186                     + klass
187                     + config.getAttributeNames();
188             log.error(errorMsg);
189             throw new AccessControlException(errorMsg, e);
190         }
191         return klass;
192     }
193
194     /**
195      * Loads teh configuration of an item from a file.
196      * @param file The file.
197      * @return A configuration.
198      * @throws AccessControlException when something went wrong.
199      */

200     protected Configuration getItemConfiguration(File JavaDoc file) throws AccessControlException {
201         DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
202         Configuration config = null;
203
204         try {
205             assert file.exists();
206             config = builder.buildFromFile(file);
207         } catch (Exception JavaDoc e) {
208             String JavaDoc errorMsg =
209                 "Exception when reading the configuration from file: " + file.getName();
210
211             // an exception occured when trying to read the configuration
212
// from the identity file.
213
log.error(errorMsg);
214             throw new AccessControlException(errorMsg, e);
215         }
216         return config;
217     }
218
219     protected void removeItem(File JavaDoc file) {
220     }
221
222     /**
223      * Returns an item for a given ID.
224      * @param id The id.
225      * @return An item.
226      */

227     public Item getItem(String JavaDoc id) {
228         try {
229             loadItems();
230         } catch (AccessControlException e) {
231             throw new IllegalStateException JavaDoc(e.getMessage());
232         }
233         return (Item) items.get(id);
234     }
235
236     /**
237      * get all items
238      *
239      * @return an array of items
240      */

241     public Item[] getItems() {
242         try {
243             loadItems();
244         } catch (AccessControlException e) {
245             throw new IllegalStateException JavaDoc(e.getMessage());
246         }
247         return (Item[]) items.values().toArray(new Item[items.values().size()]);
248     }
249
250     /**
251      * Add an Item to this manager
252      *
253      * @param item to be added
254      * @throws AccessControlException when the notification threw this exception.
255      */

256     public void add(Item item) throws AccessControlException {
257         assert item != null;
258         items.put(item.getId(), item);
259         if (log.isDebugEnabled()) {
260             log.debug("Item [" + item + "] added.");
261         }
262         notifyAdded(item);
263     }
264
265     /**
266      * Remove an item from this manager
267      * @param item to be removed
268      * @throws AccessControlException when the notification threw this exception.
269      */

270     public void remove(Item item) throws AccessControlException {
271         items.remove(item.getId());
272         if (log.isDebugEnabled()) {
273             log.debug("Item [" + item + "] removed.");
274         }
275         notifyRemoved(item);
276     }
277
278     /**
279      * Update an item.
280      * @param newItem The new version of the item.
281      * @throws AccessControlException when the notification threw this exception.
282      */

283     public void update(Item newItem) throws AccessControlException {
284         items.remove(newItem.getId());
285         items.put(newItem.getId(), newItem);
286         if (log.isDebugEnabled()) {
287             log.debug("Item [" + newItem + "] updated.");
288         }
289     }
290
291     /**
292      * Returns if the ItemManager contains an object.
293      * @param item The object.
294      * @return A boolean value.
295      */

296     public boolean contains(Item item) {
297         try {
298             loadItems();
299         } catch (AccessControlException e) {
300             throw new IllegalStateException JavaDoc(e.getMessage());
301         }
302         return items.containsValue(item);
303     }
304
305     /**
306      * Get the directory where the items are located.
307      *
308      * @return a <code>File</code>
309      */

310     public File JavaDoc getConfigurationDirectory() {
311         return configurationDirectory;
312     }
313
314     /**
315      * Get a file filter which filters for files containing items.
316      * @return a <code>FileFilter</code>
317      */

318     protected FileFilter JavaDoc getFileFilter() {
319         FileFilter JavaDoc filter = new FileFilter JavaDoc() {
320             public boolean accept(File JavaDoc pathname) {
321                 return (pathname.getName().endsWith(getSuffix()));
322             }
323         };
324
325         return filter;
326     }
327
328     /**
329      * Returns the file extension to be used.
330      * @return A string.
331      */

332     protected abstract String JavaDoc getSuffix();
333
334     private List JavaDoc itemManagerListeners = new ArrayList JavaDoc();
335
336     /**
337      * Attaches an item manager listener to this item manager.
338      * @param listener An item manager listener.
339      */

340     public void addItemManagerListener(ItemManagerListener listener) {
341         log.debug("Adding listener: [" + listener + "]");
342         if (!itemManagerListeners.contains(listener)) {
343             itemManagerListeners.add(listener);
344         }
345     }
346
347     /**
348      * Removes an item manager listener from this item manager.
349      * @param listener An item manager listener.
350      */

351     public void removeItemManagerListener(ItemManagerListener listener) {
352         log.debug("Removing listener: [" + listener + "]");
353         itemManagerListeners.remove(listener);
354     }
355
356     /**
357      * Notifies the listeners that an item was added.
358      * @param item The item that was added.
359      * @throws AccessControlException if an error occurs.
360      */

361     protected void notifyAdded(Item item) throws AccessControlException {
362         log.debug("Item was added: [" + item + "]");
363         List JavaDoc clone = new ArrayList JavaDoc(itemManagerListeners);
364         for (Iterator JavaDoc i = clone.iterator(); i.hasNext();) {
365             ItemManagerListener listener = (ItemManagerListener) i.next();
366             listener.itemAdded(item);
367         }
368     }
369
370     /**
371      * Notifies the listeners that an item was removed.
372      * @param item The item that was removed.
373      * @throws AccessControlException if an error occurs.
374      */

375     protected void notifyRemoved(Item item) throws AccessControlException {
376         log.debug("Item was removed: [" + item + "]");
377         List JavaDoc clone = new ArrayList JavaDoc(itemManagerListeners);
378         for (Iterator JavaDoc i = clone.iterator(); i.hasNext();) {
379             ItemManagerListener listener = (ItemManagerListener) i.next();
380             log.debug("Notifying listener: [" + listener + "]");
381             listener.itemRemoved(item);
382         }
383     }
384
385     /**
386      * Helper class to observe a directory for changes.
387      */

388     public static class DirectoryChangeNotifier {
389
390         /**
391          * Ctor.
392          * @param directory The directory to observe.
393          * @param filter A filter to specify the file type to observe.
394          */

395         public DirectoryChangeNotifier(File JavaDoc directory, FileFilter JavaDoc filter) {
396             this.directory = directory;
397             this.filter = filter;
398         }
399
400         private File JavaDoc directory;
401         private FileFilter JavaDoc filter;
402         private Map JavaDoc canonicalPath2LastModified = new HashMap JavaDoc();
403         private static final Category log = Category.getInstance(DirectoryChangeNotifier.class);
404
405         private Set JavaDoc addedFiles = new HashSet JavaDoc();
406         private Set JavaDoc removedFiles = new HashSet JavaDoc();
407         private Set JavaDoc changedFiles = new HashSet JavaDoc();
408
409         /**
410          * Checks if the directory has changed (a new file was added, a file was removed, a file has changed).
411          * @return A boolean value.
412          * @throws IOException when something went wrong.
413          */

414         public boolean hasChanged() throws IOException JavaDoc {
415
416             addedFiles.clear();
417             removedFiles.clear();
418             changedFiles.clear();
419
420             File JavaDoc[] files = directory.listFiles(filter);
421
422             Set JavaDoc newPathSet = new HashSet JavaDoc();
423
424             for (int i = 0; i < files.length; i++) {
425                 String JavaDoc canonicalPath = files[i].getCanonicalPath();
426                 newPathSet.add(canonicalPath);
427
428                 if (!canonicalPath2LastModified.containsKey(canonicalPath)) {
429                     addedFiles.add(new File JavaDoc(canonicalPath));
430
431                     if (log.isDebugEnabled()) {
432                         log.debug("New file: [" + canonicalPath + "]");
433                     }
434
435                 } else {
436                     Long JavaDoc lastModifiedObject = (Long JavaDoc) canonicalPath2LastModified.get(canonicalPath);
437                     long lastModified = lastModifiedObject.longValue();
438                     if (lastModified < files[i].lastModified()) {
439                         changedFiles.add(files[i]);
440                         if (log.isDebugEnabled()) {
441                             log.debug("File has changed: [" + canonicalPath + "]");
442                         }
443                     }
444                 }
445                 Long JavaDoc lastModified = new Long JavaDoc(files[i].lastModified());
446                 canonicalPath2LastModified.put(canonicalPath, lastModified);
447             }
448
449             Set JavaDoc oldPathSet = canonicalPath2LastModified.keySet();
450             String JavaDoc[] oldPaths = (String JavaDoc[]) oldPathSet.toArray(new String JavaDoc[oldPathSet.size()]);
451             for (int i = 0; i < oldPaths.length; i++) {
452                 if (!newPathSet.contains(oldPaths[i])) {
453                     removedFiles.add(new File JavaDoc(oldPaths[i]));
454                     canonicalPath2LastModified.remove(oldPaths[i]);
455                     if (log.isDebugEnabled()) {
456                         log.debug("File removed: [" + oldPaths[i] + "]");
457                     }
458                 }
459             }
460
461             return !addedFiles.isEmpty() || !removedFiles.isEmpty() || !changedFiles.isEmpty();
462         }
463
464         /**
465          * Returns the added files.
466          * @return An array of files.
467          */

468         public File JavaDoc[] getAddedFiles() {
469             return (File JavaDoc[]) addedFiles.toArray(new File JavaDoc[addedFiles.size()]);
470         }
471
472         /**
473          * Returns the removed files.
474          * @return An array of files.
475          */

476         public File JavaDoc[] getRemovedFiles() {
477             return (File JavaDoc[]) removedFiles.toArray(new File JavaDoc[removedFiles.size()]);
478         }
479
480         /**
481          * Returns the changed files.
482          * @return An array of files.
483          */

484         public File JavaDoc[] getChangedFiles() {
485             return (File JavaDoc[]) changedFiles.toArray(new File JavaDoc[changedFiles.size()]);
486         }
487
488     }
489
490 }
491
Popular Tags