Merge the recent changes from HEAD onto the branch
[beagle.git] / beagled / BackendDriver.cs
blob56cdd7d31814e3fc64e193ae581eba09594a90e3
1 //
2 // BackendDriver.cs
3 //
4 // Copyright (C) 2004-2006 Novell, Inc.
5 //
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
27 using System;
28 using System.Collections;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Reflection;
32 using System.Threading;
34 using Beagle.Util;
36 namespace Beagle.Daemon {
38 public static class BackendDriver {
40 // Contains list of backends explicitly asked by --allow-backend or --backend name
41 // These backends are exclusive, and the list of allowed backends isn't read from
42 // the configuration.
43 private static List <string> excl_allowed_backends = new List <string> ();
45 // Contains list of disable backends, either from the configuration or through
46 // --deny-baceknd or --backend -name.
47 private static List <string> denied_backends = new List <string> ();
49 public static void OnlyAllow (string name)
51 excl_allowed_backends.Add (name.ToLower ());
54 public static void Allow (string name)
56 ReadBackendsFromConf ();
58 denied_backends.Remove (name.ToLower ());
61 public static void Deny (string name)
63 ReadBackendsFromConf ();
65 name = name.ToLower ();
66 if (!denied_backends.Contains (name))
67 denied_backends.Add (name);
70 private static bool UseBackend (string name)
72 name = name.ToLower ();
74 // Check if this is an exclusively allowed backend
75 if (excl_allowed_backends.Contains (name))
76 return true;
78 // If it's not, and we have *any* exclusively allowed
79 // backends, then we can't use this backend.
80 if (excl_allowed_backends.Count > 0)
81 return false;
83 // Next, check to see if we're in the denied backends
84 // list.
85 if (denied_backends.Contains (name))
86 return false;
88 // Otherwise, we're good.
89 return true;
92 ///////////////////////////////////////////////////////////////
94 // Paths to static backends
95 private static List <string> static_backend_paths = new List <string> ();
97 public static void AddStaticBackendPath (string path)
99 if (! static_backend_paths.Contains (path))
100 static_backend_paths.Add (path);
103 ///////////////////////////////////////////////////////////////
105 private static bool done_reading_conf = false;
107 private static void ReadBackendsFromConf ()
109 if (done_reading_conf)
110 return;
112 done_reading_conf = true;
114 // If we have exclusively allowed backends, don't read
115 // from our configuration.
116 if (excl_allowed_backends.Count > 0)
117 return;
119 // To allow static indexes, "static" should be in
120 // allowed_backends
121 if (Conf.Daemon.AllowStaticBackend)
122 Allow ("static");
124 if (Conf.Daemon.DeniedBackends == null)
125 return;
127 foreach (string name in Conf.Daemon.DeniedBackends)
128 denied_backends.Add (name.ToLower ());
131 ///////////////////////////////////////////////////////////////
133 private static List <IBackend> backends = null;
135 private static void ScanAssemblyForBackends (Assembly assembly)
137 int count = 0;
139 foreach (Type type in ReflectionFu.GetTypesFromAssemblyAttribute (assembly, typeof (IBackendTypesAttribute))) {
140 foreach (BackendFlavor flavor in ReflectionFu.ScanTypeForAttribute (type, typeof (BackendFlavor))) {
141 if (! UseBackend (flavor.Name))
142 continue;
144 IBackend backend = null;
146 try {
147 backend = Activator.CreateInstance (type) as IBackend;
148 } catch (Exception e) {
149 Log.Error (e, "Unable to instantiate backend {0}", flavor.Name);
152 if (backend == null)
153 continue;
155 backend.Name = flavor.Name;
156 backend.Domain = flavor.Domain;
158 if (backends == null)
159 backends = new List <IBackend> ();
161 backends.Add (backend);
162 count++;
166 Log.Debug ("Found {0} backends in {1}", count, assembly.Location);
169 ///////////////////////////////////////////////////////////////
171 // Delay before starting the indexing process
173 static int indexing_delay = 60; // Default to 60 seconds
175 public static int IndexingDelay {
176 set { indexing_delay = value; }
179 ///////////////////////////////////////////////////////////////
181 private static ArrayList assemblies = null;
183 private static void PopulateAssemblies ()
185 if (assemblies != null)
186 return;
188 assemblies = ReflectionFu.ScanEnvironmentForAssemblies ("BEAGLE_BACKEND_PATH", PathFinder.BackendDir);
190 // Only add the executing assembly if we haven't already loaded it.
191 if (assemblies.IndexOf (Assembly.GetExecutingAssembly ()) == -1)
192 assemblies.Add (Assembly.GetExecutingAssembly ());
195 public static void Init ()
197 ReadBackendsFromConf ();
198 PopulateAssemblies ();
201 public static void LoadBackends ()
203 if (assemblies == null)
204 throw new Exception ("BackendDriver.Init() must be called before BackendDriver.LoadBackends ()");
206 foreach (Assembly assembly in assemblies) {
207 ScanAssemblyForBackends (assembly);
209 // This allows backends to define their own
210 // executors.
211 Server.ScanAssemblyForExecutors (assembly);
214 // No reason to keep around the assemblies list
215 assemblies = null;
217 // XXX: Move this into the filter loading code; it makes a lot more sense there
218 //ReadKeywordMappings ();
220 LoadSystemIndexes ();
223 public static void StartBackends ()
225 foreach (IBackend backend in backends)
226 Log.Debug (" - {0}", backend.Name);
228 if (indexing_delay <= 0 || Environment.GetEnvironmentVariable ("BEAGLE_EXERCISE_THE_DOG") != null)
229 ReallyStartBackends ();
230 else {
231 Log.Debug ("Waiting {0} seconds before starting backends", indexing_delay);
232 GLib.Timeout.Add ((uint) indexing_delay * 1000, ReallyStartBackends);
236 private static bool ReallyStartBackends ()
238 foreach (IBackend backend in backends)
239 backend.Start ();
241 return false;
244 public static ICollection <IBackend> Backends {
245 get {
246 if (backends == null)
247 throw new Exception ("BackendManager.LoadBackends() must be called before accessing BackendManager.Backends");
249 return backends;
253 ///////////////////////////////////////////////////////////////
255 private static void LoadSystemIndexes ()
257 if (! Directory.Exists (PathFinder.SystemIndexesDir))
258 return;
260 Log.Info ("Loading system-wide indexes.");
262 int count = 0;
264 foreach (DirectoryInfo index_dir in new DirectoryInfo (PathFinder.SystemIndexesDir).GetDirectories ()) {
265 if (! UseBackend (index_dir.Name))
266 continue;
268 if (LoadStaticBackend (index_dir, QueryDomain.System))
269 count++;
272 Log.Info ("Found {0} system-wide indexes.", count);
275 private static void LoadStaticBackends ()
277 int count = 0;
279 if (UseBackend ("static")) {
280 Log.Info ("Loading user-configured static indexes.");
282 foreach (string path in Conf.Daemon.StaticQueryables)
283 static_backend_paths.Add (path);
286 foreach (string path in static_backend_paths) {
287 DirectoryInfo index_dir = new DirectoryInfo (StringFu.SanitizePath (path));
289 if (!index_dir.Exists)
290 continue;
292 // FIXME: QueryDomain might be other than local
293 if (LoadStaticBackend (index_dir, QueryDomain.Local))
294 count++;
297 Log.Info ("Found {0} user-configured static indexes.", count);
300 // Instantiates and loads a StaticLuceneBackend from an index directory
301 private static bool LoadStaticBackend (DirectoryInfo index_dir, QueryDomain query_domain)
303 StaticQueryable static_backend = null;
305 if (!index_dir.Exists)
306 return false;
308 try {
309 static_backend = new StaticQueryable (index_dir.FullName);
310 } catch (InvalidOperationException) {
311 Logger.Log.Warn ("Unable to create read-only index (likely due to index version mismatch): {0}", index_dir.FullName);
312 return false;
313 } catch (Exception e) {
314 Logger.Log.Error (e, "Caught exception while instantiating static queryable: {0}", index_dir.Name);
315 return false;
318 if (static_backend != null) {
319 static_backend.Name = index_dir.Name;
320 static_backend.Domain = query_domain;
322 backends.Add (static_backend);
324 return true;
327 return false;
330 ///////////////////////////////////////////////////////////////
332 static public IBackend GetBackend (string name)
334 foreach (IBackend backend in backends) {
335 if (name == backend.Name)
336 return backend;
339 return null;
342 ///////////////////////////////////////////////////////////////
344 static public string ListBackends ()
346 string ret = "User:\n";
348 PopulateAssemblies ();
350 foreach (Assembly assembly in assemblies) {
351 foreach (Type type in ReflectionFu.GetTypesFromAssemblyAttribute (assembly, typeof (IBackendTypesAttribute))) {
352 foreach (BackendFlavor flavor in ReflectionFu.ScanTypeForAttribute (type, typeof (BackendFlavor)))
353 ret += String.Format (" - {0}\n", flavor.Name);
357 if (!Directory.Exists (PathFinder.SystemIndexesDir))
358 return ret;
360 ret += "System:\n";
361 foreach (DirectoryInfo index_dir in new DirectoryInfo (PathFinder.SystemIndexesDir).GetDirectories ()) {
362 ret += String.Format (" - {0}\n", index_dir.Name);
365 return ret;