1/*2 * Copyright 2000-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 at7 * 8 * http://www.apache.org/licenses/LICENSE-2.09 * 10 * Unless required by applicable law or agreed to in writing, software11 * 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 and14 * limitations under the License.15 */1617packageorg.apache.jetspeed.services.registry;
1819// Java classes20import java.io.Reader;
21import java.util.Hashtable;
22import java.util.Enumeration;
23import java.util.Iterator;
24import java.util.List;
25import java.util.Map;
26import java.util.Vector;
2728import javax.servlet.ServletConfig;
2930//turbine stuff31import org.apache.turbine.services.InitializationException;
32import org.apache.turbine.services.TurbineBaseService;
33import org.apache.turbine.services.TurbineServices;
34import org.apache.turbine.services.resources.ResourceService;
35import org.apache.turbine.services.servlet.ServletService;
3637// Jetspeed classes38import org.apache.jetspeed.om.registry.DBRegistry;
39import org.apache.jetspeed.om.registry.Registry;
40import org.apache.jetspeed.om.registry.RegistryEntry;
41import org.apache.jetspeed.om.registry.RegistryException;
42import org.apache.jetspeed.om.registry.base.BaseRegistry;
43import org.apache.jetspeed.om.registry.base.LocalRegistry;
44import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
45import org.apache.jetspeed.services.logging.JetspeedLogger;
4647/***48 * <p>This is an implementation of the <code>RegistryService</code>49 * based on the Jetspeed Database Persistence Manager</p>50 *51 * @author <a href="mailto:taylor@apache.org">David Sean Taylor</a>52 * @author <a href="mailto:susinha@cisco.com">Suchisubhra Sinha</a>53 * @version $Id: DatabaseRegistryService.java,v 1.6 2004/02/23 03:31:50 jford Exp $54 */55publicclassDatabaseRegistryService56extends TurbineBaseService
57 implements RegistryService , FileRegistry58 {
59privatestaticfinalJetspeedLogger logger = JetspeedLogFactoryService.getLogger(CastorRegistryService.class.getName());
6061/*** The name of this service */62publicstatic String SERVICE_NAME = "DatabaseRegistry";
6364publicstaticfinalint DEFAULT_VERBOSE = 1;
6566/*** regsitry type keyed list of entries */67private Hashtable registries = new Hashtable();
6869/*** The list of default fragments stores for newly created objects */70private Hashtable defaults = new Hashtable();
7172/*** The Castor generated RegsitryFragment objects */73private Hashtable fragments = new Hashtable();
7475/*** Associates entries with their fragments name for quick lookup */76private Hashtable entryIndex = new Hashtable();
7778/*** the Watcher object which monitors the regsitry directory */79privateDatabaseRegistryWatcher watcher = null;
8081/*** Assign the default poolname */82privatefinalstatic String POOL_NAME = "database";
838485/*** controls amount of debug output, the bigger the more output will be generated */86privateint verbose = DEFAULT_VERBOSE;
8788/*** Base class to implement */89privatestatic Hashtable baseClass = new Hashtable();
9091/***92 * Returns a Registry object for further manipulation93 *94 * @param regName the name of the registry to fetch95 * @return a Registry object if found by the manager or null96 */97publicRegistry get(String regName)
98 {
99return (Registry) registries.get(regName);
100 }
101102/***103 * List all the registry currently available to this service104 *105 * @return an Enumeration of registry names.106 */107public Enumeration getNames()
108 {
109return registries.keys();
110 }
111112/***113 * Creates a new RegistryEntry instance compatible with the current114 * Registry instance implementation115 *116 * @param regName the name of the registry to use117 * @return the newly created RegistryEntry118 */119publicRegistryEntry createEntry(String regName)
120 {
121RegistryEntry entry = null;
122Registry registry = (Registry) registries.get(regName);
123124if (registry != null)
125 {
126 entry = registry.createEntry();
127 }
128129return entry;
130 }
131132133/***134 * Returns a RegistryEntry from the named Registry.135 * This is a convenience wrapper around {@link136 * org.apache.jetspeed.om.registry.Registry#getEntry }137 *138 * @param regName the name of the registry139 * @param entryName the name of the entry to retrieve from the registry.140 * @return a RegistryEntry object if the key is found or null141 */142publicRegistryEntry getEntry(String regName, String entryName)
143 {
144try145 {
146return ((Registry) registries.get(regName)).getEntry(entryName);
147 }
148catch (RegistryException e)
149 {
150if (logger.isInfoEnabled())
151 {
152 logger.info(
153"RegistryService: Failed to retrieve "154 + entryName
155 + " from "156 + regName);
157 }
158 }
159catch (NullPointerException e)
160 {
161 logger.error(
162"DatabaseRegistryService: "163 + regName
164 + " registry is not known ");
165 logger.error(e);
166 }
167168returnnull;
169 }
170171/***172 * Add a new RegistryEntry in the named Registry.173 * This is a convenience wrapper around {@link174 * org.apache.jetspeed.om.registry.Registry#addEntry }175 *176 * @param regName the name of the registry177 * @param entry the Registry entry to add178 * @exception Sends a RegistryException if the manager can't add179 * the provided entry180 */181publicvoid addEntry(String regName, RegistryEntry entry)
182 throws RegistryException183 {
184if (entry == null)
185 {
186return;
187 }
188189LocalRegistry registry = (LocalRegistry) registries.get(regName);
190191if (registry != null)
192 {
193 String fragmentName = (String) entryIndex.get(entry.getName());
194195if (fragmentName == null)
196 {
197// either the entry was deleted or it does not exist198// in both cases, use the default fragment199 fragmentName = (String) defaults.get(regName);
200 }
201202RegistryFragment fragment =
203 (RegistryFragment) fragments.get(fragmentName);
204205//Fragment can be (and sometimes is, but should not be) null206if (fragment == null)
207 {
208 fragment = newRegistryFragment();
209 fragment.put(regName, new Vector());
210 fragments.put(fragmentName, fragment);
211 }
212else213 {
214 Vector vectRegistry = (Vector) fragment.get(regName);
215if (vectRegistry == null)
216 {
217 fragment.put(regName, new Vector());
218 }
219 }
220221synchronized (entryIndex)
222 {
223if (registry.hasEntry(entry.getName()))
224 {
225 fragment.setEntry(regName, entry);
226 registry.setLocalEntry(entry);
227 }
228else229 {
230 fragment.addEntry(regName, entry);
231 registry.addLocalEntry(entry);
232 }
233234 entryIndex.put(entry.getName(), fragmentName);
235// mark this fragment so that it's persisted next time236// the registry watcher is running237 fragment.setDirty(true);
238 }
239 }
240 }
241242/***243 * Deletes a RegistryEntry from the named Registry244 * This is a convenience wrapper around {@link245 * org.apache.jetspeed.om.registry.Registry#removeEntry }246 *247 * @param regName the name of the registry248 * @param entryName the name of the entry to remove249 */250publicvoid removeEntry(String regName, String entryName)
251 {
252if (entryName == null)
253 {
254return;
255 }
256257LocalRegistry registry = (LocalRegistry) registries.get(regName);
258259if (registry != null)
260 {
261 String fragmentName = (String) entryIndex.get(entryName);
262263if (fragmentName != null)
264 {
265RegistryFragment fragment =
266 (RegistryFragment) fragments.get(fragmentName);
267268synchronized (entryIndex)
269 {
270 fragment.removeEntry(regName, entryName);
271 entryIndex.remove(entryName);
272273// mark this fragment so that it's persisted next time274// the registry watcher is running275 fragment.setDirty(true);
276 }
277 }
278279// the entry is physically removed, remove the dangling reference280 registry.removeLocalEntry(entryName);
281 }
282 }
283284/***285 * This is the early initialization method called by the286 * Turbine <code>Service</code> framework287 */288publicsynchronizedvoid init(ServletConfig conf)
289 throws InitializationException
290 {
291int refreshRate = 0;
292 Vector names = new Vector();
293294//Ensure that the servlet service is initialized295 TurbineServices.getInstance().initService(ServletService.SERVICE_NAME, conf);
296297 ResourceService serviceConf =
298 ((TurbineServices) TurbineServices.getInstance()).getResources(SERVICE_NAME);
299300//build the map of default fragments, eahc registry must be associated301//with at least one fragment302try303 {
304 refreshRate = serviceConf.getInt("refreshRate", DEFAULT_REFRESH);
305 ResourceService defaults = serviceConf.getResources("default");
306 Iterator i = defaults.getKeys();
307308while (i.hasNext())
309 {
310 String name = (String) i.next();
311// add this name in the list of available registries312313 names.add(name);
314try315 {
316 String registryClass =
317"org.apache.jetspeed.om.registry.database.BaseJetspeed"318 + name
319 + "Peer";
320321 baseClass.put(
322 name,
323 (DBRegistry) Class
324 .forName(registryClass)
325 .newInstance());
326 }
327catch (Exception e)
328 {
329if (logger.isWarnEnabled())
330 {
331 logger.warn(
332"DatabaseRegistryService: Class "333 + name
334 + " not found");
335 }
336337 }
338339 }
340 }
341catch (Throwable t)
342 {
343thrownew InitializationException("Unable to initialize DatabaseRegistryService, missing config keys");
344 }
345346this.watcher = newDatabaseRegistryWatcher();
347this.watcher.setSubscriber(this);
348349if (refreshRate == 0)
350 {
351this.watcher.setDone();
352 }
353else354 {
355this.watcher.setRefreshRate(refreshRate);
356 }
357// changing the base will trigger a synchronous loading of the fragments358this.watcher.changeBase(names);
359360//Mark that we are done361 setInit(true);
362363// load the registries364 Enumeration en = names.elements();
365366RegistryService localeService =
367 (RegistryService) TurbineServices
368 .getInstance()
369 .getService(RegistryService.SERVICE_NAME);
370371while (en.hasMoreElements())
372 {
373 String name = (String) en.nextElement();
374Registry registry = (Registry) registries.get(name);
375376if (registry == null)
377 {
378 String registryClass = null;
379try380 {
381 registry = localeService.get(name);
382 }
383catch (Exception e)
384 {
385if (logger.isWarnEnabled())
386 {
387 logger.warn(
388"DatabaseRegistryService: Class "389 + registryClass
390 + " not found, reverting to default Registry");
391 }
392 registry = newBaseRegistry();
393 }
394 registries.put(name, registry);
395 }
396397 refresh(name);
398 }
399400// Start the directory watcher thread and rely on its refresh process401// to completely load all registries402if (this.watcher != null)
403 {
404this.watcher.start();
405 }
406407if (logger.isDebugEnabled())
408 {
409 logger.debug(
410"DatabaseRegistryService: early init()....end!, this.getInit()= "411 + getInit());
412 }
413 }
414/***415 * @return a Map of all fragments keyed by file names416 */417public Map getFragmentMap()
418 {
419return (Map) fragments.clone();
420 }
421422/*** Late init method from Turbine Service model */423publicvoid init() throws InitializationException
424 {
425if (logger.isDebugEnabled())
426 {
427 logger.debug("DatabaseRegistryService: Late init called");
428 }
429while (!getInit())
430 {
431//Not yet...432try433 {
434 Thread.sleep(500);
435if ((verbose > 2) && logger.isDebugEnabled())
436 {
437 logger.debug(
438"DatabaseRegistryService: Waiting for init of Registry...");
439 }
440 }
441catch (InterruptedException ie)
442 {
443 logger.error(ie);
444 }
445 }
446447if (logger.isDebugEnabled())
448 {
449 logger.debug("DatabaseRegistryService: We are done");
450 }
451 }
452453/***454 * This is the shutdown method called by the455 * Turbine <code>Service</code> framework456 */457publicvoid shutdown()
458 {
459this.watcher.setDone();
460461 Iterator i = fragments.keySet().iterator();
462while (i.hasNext())
463 {
464 saveFragment((String) i.next());
465 }
466 }
467468/***469 * Scan all the registry fragments for new entries relevant to470 * this registry and update its definition.471 *472 * @param regName the name of the Registry to refresh473 */474protectedvoid refresh(String regName)
475 {
476if (logger.isDebugEnabled())
477 {
478 logger.debug(
479"DatabaseRegistryService: Updating the "480 + regName
481 + " registry");
482 }
483484int count = 0;
485int counDeleted = 0;
486LocalRegistry registry = (LocalRegistry) get(regName);
487488 Vector toDelete = new Vector();
489 Iterator i = registry.listEntryNames();
490491while (i.hasNext())
492 {
493 toDelete.add(i.next());
494 }
495496if (registry == null)
497 {
498 logger.error(
499"DatabaseRegistryService: Null "500 + name
501 + " registry in refresh");
502return;
503 }
504505// for each fragment...506 Enumeration en = fragments.keys();
507while (en.hasMoreElements())
508 {
509 String location = (String) en.nextElement();
510RegistryFragment fragment =
511 (RegistryFragment) fragments.get(location);
512int fragCount = 0;
513514if (!fragment.hasChanged())
515 {
516if ((verbose > 2) && logger.isDebugEnabled())
517 {
518 logger.debug(
519"DatabaseRegistryService: Skipping fragment "520 + location);
521 }
522523//remove this fragment entries from the delete list524 Vector entries = fragment.getEntries(regName);
525 i = entries.iterator();
526while (i.hasNext())
527 {
528 toDelete.remove(((RegistryEntry) i.next()).getName());
529 }
530continue;
531 }
532533//the fragment has some changes, iterate over its entries...534 Vector entries = fragment.getEntries(regName);
535//... if it has entries related to this regsistry,536if (entries != null)
537 {
538// for all these entries539 Enumeration en2 = entries.elements();
540while (en2.hasMoreElements())
541 {
542RegistryEntry entry = (RegistryEntry) en2.nextElement();
543// update or add the entry in the registry544try545 {
546if (registry.hasEntry(entry.getName()))
547 {
548if (registry
549 .getEntry(entry.getName())
550 .equals(entry))
551 {
552if ((verbose > 2)
553 && logger.isDebugEnabled())
554 {
555 logger.debug(
556"DatabaseRegistryService: No changes to entry "557 + entry.getName());
558 }
559 }
560else561 {
562if ((verbose > 1)
563 && logger.isDebugEnabled())
564 {
565 logger.debug(
566"DatabaseRegistryService: Updating entry "567 + entry.getName()
568 + " of class "569 + entry.getClass()
570 + " to registry "571 + name);
572 }
573 registry.setLocalEntry(entry);
574// Initialize the entry index575this.entryIndex.put(entry.getName(), location);
576 ++fragCount;
577 }
578 }
579else580 {
581 registry.addLocalEntry(entry);
582// Initialize the entry index583this.entryIndex.put(entry.getName(), location);
584 ++fragCount;
585586if ((verbose > 1)
587 && logger.isDebugEnabled())
588 {
589 logger.debug(
590"DatabaseRegistryService: Adding entry "591 + entry.getName()
592 + " of class "593 + entry.getClass()
594 + " to registry "595 + name);
596 }
597 }
598 }
599catch (RegistryException e)
600 {
601 logger.error(
602"DatabaseRegistryService: RegistryException while adding "603 + entry.getName()
604 + "from "605 + location,
606 e);
607 }
608//remove this entry from the delete list609 toDelete.remove(entry.getName());
610 }
611 }
612613 count += fragCount;
614 }
615616//now delete the entries not found in any fragment617 i = toDelete.iterator();
618while (i.hasNext())
619 {
620 String entryName = (String) i.next();
621622if ((verbose > 1) && logger.isDebugEnabled())
623 {
624 logger.debug(
625"DatabaseRegistryService: removing entry " + entryName);
626 }
627//TODO may be I will do it later 628//it should delete only portlets which is coming from database629630//registry.removeLocalEntry(entryName);631 }
632633if ((verbose > 1) && logger.isDebugEnabled())
634 {
635 logger.debug(
636"DatabaseRegistryService: Merged "637 + count
638 + " entries and deleted "639 + toDelete.size()
640 + " in "641 + name);
642 }
643 }
644645// FileRegistry interface646647/*** Refresh the state of the registry implementation. Should be called648 * whenever the underlying fragments are modified649 */650publicvoid refresh()
651 {
652synchronized (watcher)
653 {
654 Enumeration en = getNames();
655while (en.hasMoreElements())
656 {
657 refresh((String) en.nextElement());
658 }
659 }
660 }
661662/***663 * Load and unmarshal a RegistryFragment from the file664 * @param file the absolute file path storing this fragment665 */666publicvoid loadFragment(String file )
667 {
668try669 {
670RegistryFragment fragment = createFragment(file);
671//mark this fragment as changed672 fragment.setChanged(true);
673674// if we get here, we successfully loaded the new fragment675 updateFragment(file, fragment);
676677 }
678catch (Throwable t)
679 {
680 logger.error(
681"DatabaseRegistryService: Could not unmarshal: " + file,
682 t);
683 }
684 }
685686/***687 * Read and unmarshal a fragment in memory688 * @param name the name of this fragment689 * @param persistent whether this fragment should be persisted on disk in690 * the registry691 */692publicvoid createFragment(
693 String name,
694 Reader reader,
695boolean persistent)
696 {
697 String file = null;
698699try700 {
701 }
702catch (Throwable t)
703 {
704 logger.error(
705"DatabaseRegistryService: Could not create fragment: " + file, t);
706 }
707finally708 {
709try710 {
711 reader.close();
712 }
713catch (Exception e)
714 {
715 logger.error(e); // At least log the exception.716 }
717 }
718 }
719/***720 * Marshal and save a RegistryFragment to disk721 * @param file the absolute file path storing this fragment722 */723publicvoid saveFragment(String file)
724 {
725726/***727 * TODO I will implement this 728 * should go to database729 */730731 }
732/***733 * Remove a fragment from storage734 * @param file the absolute file path storing this fragment735 */736publicvoid removeFragment(String file)
737 {
738RegistryFragment fragment = (RegistryFragment) fragments.get(file);
739740if (fragment != null)
741 {
742synchronized (entryIndex)
743 {
744// clear the entry index745 Iterator i = entryIndex.keySet().iterator();
746while (i.hasNext())
747 {
748if (file.equals(entryIndex.get(i.next())))
749 {
750 i.remove();
751 }
752 }
753754// make sure the keys & entries are freed for this fragment755// only the entries not replaced by the next registry refresh will756// stay in memory757 fragment.clear();
758// remove the actual fragment from memory759 fragments.remove(file);
760 }
761 }
762 }
763764/***765 * Updates a fragment in storage and the associated entryIndex766 */767protectedvoid updateFragment(String name, RegistryFragment fragment)
768 {
769synchronized (entryIndex)
770 {
771// remove the old keys772 Iterator i = entryIndex.keySet().iterator();
773while (i.hasNext())
774 {
775if (name.equals(entryIndex.get(i.next())))
776 {
777 i.remove();
778 }
779 }
780// store the new fragment781 fragments.put(name, fragment);
782783// recreate the index entries (only this fragment)784785 Enumeration enum = fragment.keys();
786while (enum.hasMoreElements())
787 {
788 String strReg = (String) enum.nextElement();
789 Vector v = fragment.getEntries(strReg);
790for (int counter = 0; counter < v.size(); counter++)
791 {
792RegistryEntry str = (RegistryEntry) v.elementAt(counter);
793 entryIndex.put(str.getName(), name);
794 }
795 }
796 }
797 }
798799//class specific implementation 800privatestatic List getData(String name)
801 {
802 List list = null;
803try804 {
805DBRegistry BaseClass = (DBRegistry) baseClass.get(name);
806if (BaseClass != null)
807 {
808 list = BaseClass.getXREGDataFromDb();
809 }
810else811 {
812 logger.warn(
813"DatabaseRegistryService: Base class for service " + name + " not found");
814 }
815 }
816catch (Exception ex)
817 {
818 logger.warn(
819"DatabaseRegistryService: Base class for service " + name + " not found");
820 }
821return list;
822 }
823824privateRegistryFragment createFragment(String regName)
825 {
826RegistryFragment fragment = (RegistryFragment) fragments.get(regName);
827828//Fragment can be (and sometimes is, but should not be) null829if (fragment == null)
830 {
831 fragment = newRegistryFragment();
832 fragment.put(regName, new Vector());
833 }
834else835 {
836 Vector vectRegistry = (Vector) fragment.get(regName);
837if (vectRegistry == null)
838 {
839 fragment.put(regName, new Vector());
840 }
841 }
842 List entries = getData(regName);
843if (entries != null)
844 {
845for (int i = 0; i < entries.size(); i++)
846 {
847 fragment.setEntry(regName, (RegistryEntry) entries.get(i));
848// mark this fragment so that it's persisted next time849// the registry watcher is running850 fragment.setDirty(true);
851 }
852 }
853else854 {
855 logger.warn(
856"DatabaseRegistryService:no data fouund for service " + name );
857858 }
859return fragment;
860861 }
862 }