4 // Copyright (C) 2004-2006 Novell, Inc.
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.
28 using System
.Collections
;
29 using System
.Collections
.Generic
;
31 using System
.Reflection
;
32 using System
.Threading
;
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
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
))
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)
83 // Next, check to see if we're in the denied backends
85 if (denied_backends
.Contains (name
))
88 // Otherwise, we're good.
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
)
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)
119 // To allow static indexes, "static" should be in
121 if (Conf
.Daemon
.AllowStaticBackend
)
124 if (Conf
.Daemon
.DeniedBackends
== null)
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
)
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
))
144 IBackend backend
= null;
147 backend
= Activator
.CreateInstance (type
) as IBackend
;
148 } catch (Exception e
) {
149 Log
.Error (e
, "Unable to instantiate backend {0}", flavor
.Name
);
155 backend
.Name
= flavor
.Name
;
156 backend
.Domain
= flavor
.Domain
;
158 if (backends
== null)
159 backends
= new List
<IBackend
> ();
161 backends
.Add (backend
);
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)
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
211 Server
.ScanAssemblyForExecutors (assembly
);
214 // No reason to keep around the assemblies list
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 ();
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
)
244 public static ICollection
<IBackend
> Backends
{
246 if (backends
== null)
247 throw new Exception ("BackendManager.LoadBackends() must be called before accessing BackendManager.Backends");
253 ///////////////////////////////////////////////////////////////
255 private static void LoadSystemIndexes ()
257 if (! Directory
.Exists (PathFinder
.SystemIndexesDir
))
260 Log
.Info ("Loading system-wide indexes.");
264 foreach (DirectoryInfo index_dir
in new DirectoryInfo (PathFinder
.SystemIndexesDir
).GetDirectories ()) {
265 if (! UseBackend (index_dir
.Name
))
268 if (LoadStaticBackend (index_dir
, QueryDomain
.System
))
272 Log
.Info ("Found {0} system-wide indexes.", count
);
275 private static void LoadStaticBackends ()
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
)
292 // FIXME: QueryDomain might be other than local
293 if (LoadStaticBackend (index_dir
, QueryDomain
.Local
))
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
)
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
);
313 } catch (Exception e
) {
314 Logger
.Log
.Error (e
, "Caught exception while instantiating static queryable: {0}", index_dir
.Name
);
318 if (static_backend
!= null) {
319 static_backend
.Name
= index_dir
.Name
;
320 static_backend
.Domain
= query_domain
;
322 backends
.Add (static_backend
);
330 ///////////////////////////////////////////////////////////////
332 static public IBackend
GetBackend (string name
)
334 foreach (IBackend backend
in backends
) {
335 if (name
== backend
.Name
)
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
))
361 foreach (DirectoryInfo index_dir
in new DirectoryInfo (PathFinder
.SystemIndexesDir
).GetDirectories ()) {
362 ret
+= String
.Format (" - {0}\n", index_dir
.Name
);