View Javadoc

1   /*
2    * Copyright 2000-2001,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  package org.apache.jetspeed.services.registry;
18  
19  // Jetspeed stuff
20  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
21  import org.apache.jetspeed.services.logging.JetspeedLogger;
22  import org.apache.jetspeed.om.registry.Registry;
23  import org.apache.jetspeed.om.registry.RegistryEntry;
24  import org.apache.jetspeed.om.registry.RegistryException;
25  import org.apache.jetspeed.om.registry.base.BaseRegistry;
26  import org.apache.jetspeed.om.registry.base.LocalRegistry;
27  
28  //turbine stuff
29  import org.apache.turbine.services.InitializationException;
30  import org.apache.turbine.services.TurbineBaseService;
31  import org.apache.turbine.services.TurbineServices;
32  import org.apache.turbine.services.servlet.TurbineServlet;
33  import org.apache.turbine.services.servlet.ServletService;
34  import org.apache.turbine.services.resources.ResourceService;
35  
36  // castor marshalling
37  import org.exolab.castor.mapping.Mapping;
38  import org.exolab.castor.xml.Unmarshaller;
39  import org.exolab.castor.xml.Marshaller;
40  import org.xml.sax.InputSource;
41  import org.apache.xml.serialize.Serializer;
42  import org.apache.xml.serialize.XMLSerializer;
43  import org.apache.xml.serialize.OutputFormat;
44  import org.w3c.dom.Document;
45  import org.w3c.dom.Node;
46  
47  //java stuff
48  import java.io.File;
49  import java.io.FileFilter;
50  import java.io.FileReader;
51  import java.io.FileOutputStream;
52  import java.io.OutputStreamWriter;
53  import java.io.Reader;
54  import java.util.Enumeration;
55  import java.util.Hashtable;
56  import java.util.Map;
57  import java.util.Iterator;
58  import java.util.Vector;
59  import javax.servlet.ServletConfig;
60  import javax.xml.parsers.DocumentBuilder;
61  import javax.xml.parsers.DocumentBuilderFactory;
62  
63  /***
64   * <p>This is an implementation of the <code>RegistryService</code>
65   * based on the Castor XML serialization mechanisms</p>
66   * <p>This registry aggregates multiple RegistryFragment to store the regsistry
67   * entries</p>
68   *
69   * <p>This service expects the following properties to be set for correct operation:
70   * <dl>
71   *    <dt>directory</dt><dd>The directory where the Registry will look for
72   *    fragment files</dd>
73   *    <dt>extension</dt><dd>The extension used for identifying the registry fragment
74   *    files. Default .xreg</dd>
75   *    <dt>mapping</dt><dd>the Castor object mapping file path</dd>
76   *    <dt>registries</dt><dd>a comma separated list of registry names to load
77   *     from this file</dd>
78   *    <dt>refreshRate</dt><dd>Optional. The manager will check every
79   *     refreshRate seconds if the config has changed and if true will refresh
80   *     all the registries. A value of 0 or negative will disable the
81   *     automatic refresh operation. Default: 300 (5 minutes)</dd>
82    * </dl>
83   * </p>
84   *
85   * @author <a href="mailto:raphael@apache.org">Raphaël Luta</a>
86   * @author <a href="mailto:sgala@apache.org">Santiago Gala</a>
87   * @version $Id: CastorRegistryService.java,v 1.37 2004/03/31 00:23:02 jford Exp $
88   */
89  public class CastorRegistryService
90      extends TurbineBaseService
91      implements RegistryService, FileRegistry
92  {
93      /***
94       * Static initialization of the logger for this class
95       */    
96      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(CastorRegistryService.class.getName());
97      
98      public static final int DEFAULT_REFRESH = 300;
99      public static final String DEFAULT_EXTENSION = ".xreg";
100     public static final String DEFAULT_MAPPING = "${webapp}/WEB-INF/conf/mapping.xml";
101 
102     /*** regsitry type keyed list of entries */
103     private Hashtable registries = new Hashtable();
104 
105     /*** The Castor generated RegsitryFragment objects */
106     private Hashtable fragments = new Hashtable();
107 
108     /*** The list of default fragments stores for newly created objects */
109     private Hashtable defaults = new Hashtable();
110 
111     /*** Associates entries with their fragments name for quick lookup */
112     private Hashtable entryIndex = new Hashtable();
113 
114     /*** the Watcher object which monitors the regsitry directory */
115     private RegistryWatcher watcher = null;
116 
117     /*** the Castor mapping file name */
118     private Mapping mapping = null;
119 
120     /*** the output format for pretty printing when saving registries */
121     private OutputFormat format = null;
122 
123     /*** the base regsitry directory */
124     private String directory = null;
125 
126     /*** the extension for registry files */
127     private String extension = null;
128 
129     /***
130      * Returns a Registry object for further manipulation
131      *
132      * @param regName the name of the registry to fetch
133      * @return a Registry object if found by the manager or null
134      */
135     public Registry get(String regName)
136     {
137         return (Registry) registries.get(regName);
138     }
139 
140     /***
141      *  List all the registry currently available to this service
142      *
143      * @return an Enumeration of registry names.
144      */
145     public Enumeration getNames()
146     {
147         return registries.keys();
148     }
149 
150     /***
151      * Creates a new RegistryEntry instance compatible with the current
152      * Registry instance implementation
153      *
154      * @param regName the name of the registry to use
155      * @return the newly created RegistryEntry
156      */
157     public RegistryEntry createEntry(String regName)
158     {
159                 RegistryEntry entry = null;
160         Registry registry = (Registry) registries.get(regName);
161 
162         if (registry != null)
163         {
164             entry = registry.createEntry();
165         }
166 
167         return entry;
168     }
169 
170     /***
171      * Returns a RegistryEntry from the named Registry.
172      * This is a convenience wrapper around {@link
173      * org.apache.jetspeed.om.registry.Registry#getEntry }
174      *
175      * @param regName the name of the registry
176      * @param entryName the name of the entry to retrieve from the
177      *                  registry
178      * @return a RegistryEntry object if the key is found or null
179      */
180     public RegistryEntry getEntry(String regName, String entryName)
181     {
182         try
183         {
184             return ((Registry) registries.get(regName)).getEntry(entryName);
185         }
186         catch (RegistryException e)
187         {
188             if (logger.isInfoEnabled())
189             {
190                 logger.info("RegistryService: Failed to retrieve " + entryName + " from " + regName);
191             }
192         }
193         catch (NullPointerException e)
194         {
195             logger.error("RegistryService: " + regName + " registry is not known ", e);
196         }
197 
198         return null;
199     }
200 
201     /***
202      * Add a new RegistryEntry in the named Registry.
203      * This is a convenience wrapper around {@link
204      * org.apache.jetspeed.om.registry.Registry#addEntry }
205      *
206      * @param regName the name of the registry
207      * @param entry the Registry entry to add
208      * @exception Sends a RegistryException if the manager can't add
209      *            the provided entry
210      */
211     public void addEntry(String regName, RegistryEntry entry) throws RegistryException
212     {
213         if (entry == null)
214         {
215             return;
216         }
217 
218 		LocalRegistry registry = (LocalRegistry) registries.get(regName);
219 
220         if (registry != null)
221         {
222             String fragmentName = (String) entryIndex.get(entry.getName());
223 
224             if (fragmentName == null)
225             {
226                 // either the entry was deleted or it does not exist
227                 // in both cases, use the default fragment
228                 fragmentName = (String) defaults.get(regName);
229             }
230 
231             RegistryFragment fragment = (RegistryFragment) fragments.get(fragmentName);
232 
233             //Fragment can be (and sometimes is, but should not be) null
234             if (fragment == null)
235             {
236                 fragment = new RegistryFragment();
237                 fragment.put(regName, new Vector());
238                 fragments.put(fragmentName, fragment);
239             }
240             else
241             {
242                 Vector vectRegistry = (Vector) fragment.get(regName);
243                 if (vectRegistry == null)
244                 {
245                     fragment.put(regName, new Vector());
246                 }
247             }
248 
249             synchronized (entryIndex)
250             {
251                 if (registry.hasEntry(entry.getName()))
252                 {
253                     fragment.setEntry(regName, entry);
254                     registry.setLocalEntry(entry);
255                 }
256                 else
257                 {
258                     fragment.addEntry(regName, entry);
259                     registry.addLocalEntry(entry);
260                 }
261 
262                 entryIndex.put(entry.getName(), fragmentName);
263                 // mark this fragment so that it's persisted next time
264                 // the registry watcher is running
265                 fragment.setDirty(true);
266             }
267         }
268     }
269 
270     /***
271      * Deletes a RegistryEntry from the named Registry
272      * This is a convenience wrapper around {@link
273      * org.apache.jetspeed.om.registry.Registry#removeEntry }
274      *
275      * @param regName the name of the registry
276      * @param entryName the name of the entry to remove
277      */
278     public void removeEntry(String regName, String entryName)
279     {
280         if (entryName == null)
281         {
282             return;
283         }
284 
285 		LocalRegistry registry = (LocalRegistry) registries.get(regName);
286 
287         if (registry != null)
288         {
289             String fragmentName = (String) entryIndex.get(entryName);
290 
291             if (fragmentName != null)
292             {
293                 RegistryFragment fragment = (RegistryFragment) fragments.get(fragmentName);
294 
295                 synchronized (entryIndex)
296                 {
297                     fragment.removeEntry(regName, entryName);
298                     entryIndex.remove(entryName);
299 
300                     // mark this fragment so that it's persisted next time
301                     // the registry watcher is running
302                     fragment.setDirty(true);
303                 }
304             }
305 
306             // the entry is physically removed, remove the dangling reference
307             registry.removeLocalEntry(entryName);
308         }
309     }
310 
311     /***
312      * This is the early initialization method called by the
313      * Turbine <code>Service</code> framework
314      */
315     public synchronized void init(ServletConfig conf) throws InitializationException
316     {
317 
318         //Ensure that the servlet service is initialized
319         TurbineServices.getInstance().initService(ServletService.SERVICE_NAME, conf);
320 
321         ResourceService serviceConf = ((TurbineServices) TurbineServices.getInstance())
322                                                      .getResources(RegistryService.SERVICE_NAME);
323         String mapFile = null;
324         Vector names = new Vector();
325         int refreshRate = 0;
326 
327         // read the configuration keys
328         try
329         {
330             directory = serviceConf.getString("directory");
331             mapFile = serviceConf.getString("mapping", DEFAULT_MAPPING);
332             extension = serviceConf.getString("extension", DEFAULT_EXTENSION);
333             refreshRate = serviceConf.getInt("refreshRate", DEFAULT_REFRESH);
334 
335             mapFile = TurbineServlet.getRealPath(mapFile);
336             directory = TurbineServlet.getRealPath(directory);
337         }
338         catch (Throwable t)
339         {
340             throw new InitializationException("Unable to initialize CastorRegistryService, missing config keys");
341         }
342 
343         // build the map of default fragments, eahc registry must be associated
344         // with at least one fragment
345         try
346         {
347             ResourceService defaults = serviceConf.getResources("default");
348             Iterator i = defaults.getKeys();
349             while (i.hasNext())
350             {
351                 String name = (String) i.next();
352                 String fragmentFileName = defaults.getString(name);
353 
354                 String absFileName = new File(directory, fragmentFileName + extension).getCanonicalPath();
355                 // add this name in the list of available registries
356                 names.add(name);
357 
358                 // store the default file mapping
359                 this.defaults.put(name, absFileName);
360             }
361         }
362         catch (Exception e)
363         {
364             logger.error("RegistryService: Registry init error", e);
365             throw new InitializationException("Unable to initialize CastorRegistryService, invalid registries definition");
366         }
367 
368         // create the serializer output format
369         this.format = new OutputFormat();
370         format.setIndenting(true);
371         format.setIndent(4);
372         format.setLineWidth(0);
373 
374         // test the mapping file and create the mapping object
375 
376         if (mapFile != null)
377         {
378             File map = new File(mapFile);
379             if (map.exists() && map.isFile() && map.canRead())
380             {
381                 try
382                 {
383                     mapping = new Mapping();
384                     InputSource is = new InputSource(new FileReader(map));
385                     is.setSystemId(mapFile);
386                     mapping.loadMapping(is);
387                 }
388                 catch (Exception e)
389                 {
390                     logger.error("RegistryService: Error in mapping creation", e);
391                     throw new InitializationException("Error in mapping", e);
392                 }
393             }
394             else
395             {
396                 throw new InitializationException("Mapping not found or not a file or unreadable: " + mapFile);
397             }
398         }
399 
400         // Set directory watcher if directory exists
401         File base = new File(directory);
402         File[] files = null;
403 
404         if (base.exists() && base.isDirectory() && base.canRead())
405         {
406             this.watcher = new RegistryWatcher();
407             this.watcher.setSubscriber(this);
408             this.watcher.setFilter(new ExtFileFilter(extension));
409             if (refreshRate == 0)
410             {
411                 this.watcher.setDone();
412             }
413             else
414             {
415                 this.watcher.setRefreshRate(refreshRate);
416             }
417             // changing the base will trigger a synchronous loading of the fragments
418             this.watcher.changeBase(base);
419         }
420 
421         //Mark that we are done
422         setInit(true);
423 
424 
425         // load the registries
426         Enumeration en = names.elements();
427 
428         while (en.hasMoreElements())
429         {
430             String name = (String) en.nextElement();
431             Registry registry = (Registry) registries.get(name);
432 
433             if (registry == null)
434             {
435                 String registryClass = null;
436                 try
437                 {
438                     registryClass =
439                         "org.apache.jetspeed.om.registry.base.Base"
440                         + name
441                         + "Registry";
442 
443                     registry = (Registry) Class.forName(registryClass).newInstance();
444                 }
445                 catch (Exception e)
446                 {
447                     if (logger.isWarnEnabled())
448                     {
449                         logger.warn("RegistryService: Class "
450                                     + registryClass
451                                     + " not found, reverting to default Registry");
452                     }
453                     registry = new BaseRegistry();
454                 }
455 
456                 registries.put(name, registry);
457             }
458 
459             refresh(name);
460         }
461 
462         // Start the directory watcher thread and rely on its refresh process
463         // to completely load all registries
464         if (this.watcher != null)
465         {
466             this.watcher.start();
467         }
468 
469         if (logger.isDebugEnabled())
470         {
471             logger.debug("RegistryService: early init()....end!, this.getInit()= " + getInit());
472         }
473 
474     }
475 
476 
477     /*** Late init method from Turbine Service model */
478     public void init() throws InitializationException
479     {
480         if (logger.isDebugEnabled())
481         {
482             logger.debug("RegistryService: Late init called");
483         }
484 
485         while (!getInit())
486         {
487             //Not yet...
488             try
489             {
490                 Thread.sleep(500);
491                 if (logger.isDebugEnabled())
492                 {
493                     logger.debug("RegistryService: Waiting for init of Registry...");
494                 }
495             }
496             catch (InterruptedException ie)
497             {
498                 logger.error("Exception", ie);
499             }
500         }
501 
502         if (logger.isDebugEnabled())
503         {
504             logger.debug("RegistryService: We are done");
505         }
506     }
507 
508     /***
509      * This is the shutdown method called by the
510      * Turbine <code>Service</code> framework
511      */
512     public void shutdown()
513     {
514         this.watcher.setDone();
515 
516         Iterator i = fragments.keySet().iterator();
517         while (i.hasNext())
518         {
519             saveFragment((String) i.next());
520         }
521     }
522 
523     // FileRegistry interface
524 
525     /*** Refresh the state of the registry implementation. Should be called
526      *   whenever the underlying fragments are modified
527      */
528     public void refresh()
529     {
530         synchronized (watcher)
531         {
532             Enumeration en = getNames();
533             while (en.hasMoreElements())
534             {
535                 refresh((String) en.nextElement());
536             }
537         }
538     }
539 
540     /***
541      * @return a Map of all fragments keyed by file names
542      */
543     public Map getFragmentMap()
544     {
545         return (Map) fragments.clone();
546     }
547 
548     /***
549      * Load and unmarshal a RegistryFragment from the file
550      * @param file the absolute file path storing this fragment
551      */
552     public void loadFragment(String file)
553     {
554         try
555         {
556             DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance();
557             DocumentBuilder builder = dbfactory.newDocumentBuilder();
558        
559             Document d = builder.parse(new File(file));
560 
561             Unmarshaller unmarshaller = new Unmarshaller(this.mapping);
562             RegistryFragment fragment = (RegistryFragment) unmarshaller.unmarshal((Node) d);
563 
564             //mark this fragment as changed
565             fragment.setChanged(true);
566 
567             // if we get here, we successfully loaded the new fragment
568             updateFragment(file, fragment);
569 
570         }
571         catch (Throwable t)
572         {
573             logger.error("RegistryService: Could not unmarshal: " + file, t);
574         }
575 
576     }
577 
578     /***
579      * Read and unmarshal a fragment in memory
580      * @param name the name of this fragment
581      * @param reader the reader to use for creating this fragment
582      * @param persistent whether this fragment should be persisted on disk in
583      * the registry
584      */
585     public void createFragment(String name, Reader reader, boolean persistent)
586     {
587         String file = null;
588 
589         try
590         {
591             synchronized(watcher)
592             {
593                 file = new File(directory, name + extension).getCanonicalPath();
594     
595                 Unmarshaller unmarshaller = new Unmarshaller(this.mapping);
596                 RegistryFragment fragment = (RegistryFragment) unmarshaller.unmarshal(reader);
597     
598                 fragment.setChanged(true);
599     
600                 updateFragment(file, fragment);
601     
602                 if (persistent)
603                 {
604                     saveFragment(file);
605                 }
606             }
607         }
608         catch (Throwable t)
609         {
610             logger.error("RegistryService: Could not create fragment: " + file, t);
611         }
612         finally
613         {
614             try
615             {
616                 reader.close();
617             }
618             catch (Exception e)
619             {
620                 logger.error("Exception", e);  // At least log the exception.
621             }
622         }
623     }
624 
625     /***
626      * Marshal and save a RegistryFragment to disk
627      * @param file the absolute file path storing this fragment
628      */
629     public void saveFragment(String file)
630     {
631         OutputStreamWriter writer = null;
632         FileOutputStream fos = null;
633         String encoding = new String("UTF-8");
634         RegistryFragment fragment = (RegistryFragment) fragments.get(file);
635 
636         if (fragment != null)
637         {
638             try
639             {
640             	fos = new FileOutputStream(file);
641                 writer = new OutputStreamWriter(fos, encoding);
642                 format.setEncoding(encoding);
643                 Serializer serializer = new XMLSerializer(writer, format);
644                 Marshaller marshaller = new Marshaller(serializer.asDocumentHandler());
645                 marshaller.setMapping(this.mapping);
646                 marshaller.marshal(fragment);
647             }
648             catch (Throwable t)
649             {
650                 logger.error("RegistryService: Could not marshal: " + file, t);
651             }
652             finally
653             {
654                 try
655                 {
656                     writer.close();
657                 }
658                 catch (Exception e)
659                 {
660                     logger.error("Exception", e);  // At least log the exception.
661                 }
662                 
663                 try
664                 {
665                     fos.close();
666                 }
667                 catch (Exception e)
668                 {
669                     logger.error("Exception", e);  // At least log the exception.
670                 }
671             }
672         }
673     }
674 
675     /***
676      * Remove a fragment from storage
677      * @param file the absolute file path storing this fragment
678      */
679     public void removeFragment(String file)
680     {
681         RegistryFragment fragment = (RegistryFragment) fragments.get(file);
682 
683         if (fragment != null)
684         {
685             synchronized (entryIndex)
686             {
687                 // clear the entry index
688                 Iterator i = entryIndex.keySet().iterator();
689                 while (i.hasNext())
690                 {
691                     if (file.equals(entryIndex.get(i.next())))
692                     {
693                         i.remove();
694                     }
695                 }
696 
697                 // make sure the keys & entries are freed for this fragment
698                 // only the entries not replaced by the next registry refresh will
699                 // stay in memory
700                 fragment.clear();
701                 // remove the actual fragment from memory
702                 fragments.remove(file);
703             }
704         }
705     }
706 
707     // Implementation specific methods
708 
709     /***
710      * Updates a fragment in storage and the associated entryIndex
711      */
712     protected void updateFragment(String name, RegistryFragment fragment)
713     {
714         synchronized (entryIndex)
715         {
716             // remove the old keys
717             Iterator i = entryIndex.keySet().iterator();
718             while (i.hasNext())
719             {
720                 if (name.equals(entryIndex.get(i.next())))
721                 {
722                     i.remove();
723                 }
724             }
725 
726             // store the new fragment
727             fragments.put(name, fragment);
728 
729             // recreate the index entries (only this fragment)
730 
731             Enumeration enum = fragment.keys();
732             while (enum.hasMoreElements())
733             {
734                 String strReg = (String) enum.nextElement();
735                 Vector v = fragment.getEntries(strReg);
736 
737                 for (int counter = 0; counter < v.size(); counter++)
738                 {
739                     RegistryEntry str = (RegistryEntry) v.elementAt(counter);
740                     entryIndex.put(str.getName(), name);
741                 }
742             }
743         }
744     }
745 
746     /***
747      * Scan all the registry fragments for new entries relevant to
748      * this registry and update its definition.
749      *
750      * @param regName the name of the Registry to refresh
751      */
752     protected void refresh(String regName)
753     {
754 
755         if (logger.isDebugEnabled())
756         {
757             logger.debug("RegistryService: Updating the " + regName + " registry");
758         }
759 
760         int count = 0;
761         int counDeleted = 0;
762         LocalRegistry registry = (LocalRegistry) get(regName);
763 
764         Vector toDelete = new Vector();
765         Iterator i = registry.listEntryNames();
766 
767         while (i.hasNext())
768         {
769             toDelete.add(i.next());
770         }
771 
772         if (registry == null)
773         {
774             logger.error("RegistryService: Null " + name + " registry in refresh");
775             return;
776         }
777 
778         // for each fragment...
779         Enumeration en = fragments.keys();
780         while (en.hasMoreElements())
781         {
782             String location = (String) en.nextElement();
783             RegistryFragment fragment = (RegistryFragment) fragments.get(location);
784             int fragCount = 0;
785 
786             if (!fragment.hasChanged())
787             {
788                 if (logger.isDebugEnabled())
789                 {
790                     logger.debug("RegistryService: Skipping fragment " + location);
791                 }
792 
793                 //remove this fragment entries from the delete list
794                 Vector entries = fragment.getEntries(regName);
795                 i = entries.iterator();
796                 while (i.hasNext())
797                 {
798                     toDelete.remove(((RegistryEntry) i.next()).getName());
799                 }
800 
801                 continue;
802             }
803 
804             //the fragment has some changes, iterate over its entries...
805 
806             Vector entries = fragment.getEntries(regName);
807 
808             //... if it has entries related to this regsistry,
809             if (entries != null)
810             {
811                 // for all these entries
812                 Enumeration en2 = entries.elements();
813                 while (en2.hasMoreElements())
814                 {
815                     RegistryEntry entry = (RegistryEntry) en2.nextElement();
816                     // update or add the entry in the registry
817                     try
818                     {
819                         if (registry.hasEntry(entry.getName()))
820                         {
821                             if (registry.getEntry(entry.getName()).equals(entry))
822                             {
823                                 if (logger.isDebugEnabled())
824                                 {
825                                     logger.debug("RegistryService: No changes to entry " + entry.getName());
826                                 }
827                             }
828                             else
829                             {
830                                 if (logger.isDebugEnabled())
831                                 {
832                                     logger.debug("RegistryService: Updating entry " + entry.getName() 
833                                         + " of class " + entry.getClass() + " to registry " + name);
834                                 }
835 
836                                 registry.setLocalEntry(entry);
837                                 // Initialize the entry index
838                                 this.entryIndex.put(entry.getName(), location);
839                                 ++fragCount;
840                             }
841                         }
842                         else
843                         {
844                             registry.addLocalEntry(entry);
845                             // Initialize the entry index
846                             this.entryIndex.put(entry.getName(), location);
847                             ++fragCount;
848 
849                             if (logger.isDebugEnabled())
850                             {
851                                 logger.debug("RegistryService: Adding entry " + entry.getName() + " of class " 
852                                     + entry.getClass() + " to registry " + name);
853                             }
854                         }
855                     }
856                     catch (RegistryException e)
857                     {
858                         logger.error("RegistryService: RegistryException while adding " + entry.getName() + "from " + location, e);
859                     }
860 
861                     //remove this entry from the delete list
862                     toDelete.remove(entry.getName());
863                 }
864             }
865 
866             count += fragCount;
867         }
868 
869         //now delete the entries not found in any fragment
870         i = toDelete.iterator();
871         while (i.hasNext())
872         {
873             String entryName = (String) i.next();
874 
875             if (logger.isDebugEnabled())
876             {
877                 logger.debug("RegistryService: removing entry " + entryName);
878             }
879 
880             registry.removeLocalEntry(entryName);
881         }
882 
883 
884         if (logger.isDebugEnabled())
885         {
886             logger.debug("RegistryService: Merged " + count + " entries and deleted " + toDelete.size() + " in " + name);
887         }
888     }
889 
890 
891     /*** FileFilter implementing a file extension based filter */
892     class ExtFileFilter implements FileFilter
893     {
894         private String extension = null;
895 
896         ExtFileFilter(String extension)
897         {
898             this.extension = extension;
899         }
900 
901         public boolean accept(File f)
902         {
903             return f.toString().endsWith(extension);
904         }
905     }
906 
907 }