~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/mono-addins/Mono.Addins/Mono.Addins/AddinEngine.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// AddinService.cs
 
3
//
 
4
// Author:
 
5
//   Lluis Sanchez Gual
 
6
//
 
7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
 
8
//
 
9
// Permission is hereby granted, free of charge, to any person obtaining
 
10
// a copy of this software and associated documentation files (the
 
11
// "Software"), to deal in the Software without restriction, including
 
12
// without limitation the rights to use, copy, modify, merge, publish,
 
13
// distribute, sublicense, and/or sell copies of the Software, and to
 
14
// permit persons to whom the Software is furnished to do so, subject to
 
15
// the following conditions:
 
16
// 
 
17
// The above copyright notice and this permission notice shall be
 
18
// included in all copies or substantial portions of the Software.
 
19
// 
 
20
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
21
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
22
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
23
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
24
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
25
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
26
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
27
//
 
28
 
 
29
 
 
30
using System;
 
31
using System.Linq;
 
32
using System.Xml;
 
33
using System.Collections;
 
34
using System.Reflection;
 
35
 
 
36
using Mono.Addins.Description;
 
37
using Mono.Addins.Database;
 
38
using Mono.Addins.Localization;
 
39
using System.Collections.Generic;
 
40
 
 
41
namespace Mono.Addins
 
42
{
 
43
        /// <summary>
 
44
        /// An add-in engine.
 
45
        /// </summary>
 
46
        /// <remarks>
 
47
        /// This class allows hosting several independent add-in engines in a single application domain.
 
48
        /// In general, applications use the AddinManager class to query and manage extensions. This class is static,
 
49
        /// so the API is easily accessible. However, some kind applications may need to use several isolated
 
50
        /// add-in engines, and in this case the AddinManager class can't be used, because it is bound to a single
 
51
        /// add-in engine. Those applications can instead create several instances of the AddinEngine class. Each
 
52
        /// add-in engine can be independently initialized with different add-in registries and extension models.
 
53
        /// </remarks>
 
54
        public class AddinEngine: ExtensionContext
 
55
        {
 
56
                bool initialized;
 
57
                string startupDirectory;
 
58
                AddinRegistry registry;
 
59
                IAddinInstaller installer;
 
60
                
 
61
                bool checkAssemblyLoadConflicts;
 
62
                Hashtable loadedAddins = new Hashtable ();
 
63
                Dictionary<string,ExtensionNodeSet> nodeSets = new Dictionary<string, ExtensionNodeSet> ();
 
64
                Hashtable autoExtensionTypes = new Hashtable ();
 
65
                Hashtable loadedAssemblies = new Hashtable ();
 
66
                AddinLocalizer defaultLocalizer;
 
67
                IProgressStatus defaultProgressStatus = new ConsoleProgressStatus (false);
 
68
                
 
69
                /// <summary>
 
70
                /// Raised when there is an error while loading an add-in
 
71
                /// </summary>
 
72
                public static event AddinErrorEventHandler AddinLoadError;
 
73
                
 
74
                /// <summary>
 
75
                /// Raised when an add-in is loaded
 
76
                /// </summary>
 
77
                public static event AddinEventHandler AddinLoaded;
 
78
                
 
79
                /// <summary>
 
80
                /// Raised when an add-in is unloaded
 
81
                /// </summary>
 
82
                public static event AddinEventHandler AddinUnloaded;
 
83
                
 
84
                /// <summary>
 
85
                /// Initializes a new instance of the <see cref="Mono.Addins.AddinEngine"/> class.
 
86
                /// </summary>
 
87
                public AddinEngine ()
 
88
                {
 
89
                }
 
90
                
 
91
                /// <summary>
 
92
                /// Initializes the add-in engine
 
93
                /// </summary>
 
94
                /// <param name="configDir">
 
95
                /// Location of the add-in registry.
 
96
                /// </param>
 
97
                /// <remarks>The add-in engine needs to be initialized before doing any add-in operation.
 
98
                /// When initialized with this method, it will look for add-in in the add-in registry
 
99
                /// located in the specified path.
 
100
                /// </remarks>
 
101
                public void Initialize (string configDir)
 
102
                {
 
103
                        if (initialized)
 
104
                                return;
 
105
                        
 
106
                        Assembly asm = Assembly.GetEntryAssembly ();
 
107
                        if (asm == null) asm = Assembly.GetCallingAssembly ();
 
108
                        Initialize (asm, configDir, null, null);
 
109
                }
 
110
                
 
111
                /// <summary>
 
112
                /// Initializes the add-in engine.
 
113
                /// </summary>
 
114
                /// <param name='configDir'>
 
115
                /// Location of the add-in registry.
 
116
                /// </param>
 
117
                /// <param name='addinsDir'>
 
118
                /// Add-ins directory. If the path is relative, it is considered to be relative
 
119
                /// to the configDir directory.
 
120
                /// </param>
 
121
                /// <remarks>
 
122
                /// The add-in engine needs to be initialized before doing any add-in operation.
 
123
                /// Configuration information about the add-in registry will be stored in the
 
124
                /// provided location. The add-in engine will look for add-ins in the provided
 
125
                /// 'addinsDir' directory.
 
126
                /// 
 
127
                /// When specifying a path, it is possible to use a special folder name as root.
 
128
                /// For example: [Personal]/.config/MyApp. In this case, [Personal] will be replaced
 
129
                /// by the location of the Environment.SpecialFolder.Personal folder. Any value
 
130
                /// of the Environment.SpecialFolder enumeration can be used (always between square
 
131
                /// brackets)
 
132
                /// </remarks>
 
133
                public void Initialize (string configDir, string addinsDir)
 
134
                {
 
135
                        if (initialized)
 
136
                                return;
 
137
                        
 
138
                        Assembly asm = Assembly.GetEntryAssembly ();
 
139
                        if (asm == null) asm = Assembly.GetCallingAssembly ();
 
140
                        Initialize (asm, configDir, addinsDir, null);
 
141
                }
 
142
                
 
143
                /// <summary>
 
144
                /// Initializes the add-in engine.
 
145
                /// </summary>
 
146
                /// <param name='configDir'>
 
147
                /// Location of the add-in registry.
 
148
                /// </param>
 
149
                /// <param name='addinsDir'>
 
150
                /// Add-ins directory. If the path is relative, it is considered to be relative
 
151
                /// to the configDir directory.
 
152
                /// </param>
 
153
                /// <param name='databaseDir'>
 
154
                /// Location of the add-in database. If the path is relative, it is considered to be relative
 
155
                /// to the configDir directory.
 
156
                /// </param>
 
157
                /// <remarks>
 
158
                /// The add-in engine needs to be initialized before doing any add-in operation.
 
159
                /// Configuration information about the add-in registry will be stored in the
 
160
                /// provided location. The add-in engine will look for add-ins in the provided
 
161
                /// 'addinsDir' directory. Cached information about add-ins will be stored in
 
162
                /// the 'databaseDir' directory.
 
163
                /// 
 
164
                /// When specifying a path, it is possible to use a special folder name as root.
 
165
                /// For example: [Personal]/.config/MyApp. In this case, [Personal] will be replaced
 
166
                /// by the location of the Environment.SpecialFolder.Personal folder. Any value
 
167
                /// of the Environment.SpecialFolder enumeration can be used (always between square
 
168
                /// brackets)
 
169
                /// </remarks>
 
170
                public void Initialize (string configDir, string addinsDir, string databaseDir)
 
171
                {
 
172
                        if (initialized)
 
173
                                return;
 
174
                        
 
175
                        Assembly asm = Assembly.GetEntryAssembly ();
 
176
                        if (asm == null) asm = Assembly.GetCallingAssembly ();
 
177
                        Initialize (asm, configDir, addinsDir, databaseDir);
 
178
                }
 
179
                
 
180
                internal void Initialize (Assembly startupAsm, string configDir, string addinsDir, string databaseDir)
 
181
                {
 
182
                        if (initialized)
 
183
                                return;
 
184
                        
 
185
                        Initialize (this);
 
186
                        
 
187
                        string asmFile = new Uri (startupAsm.CodeBase).LocalPath;
 
188
                        startupDirectory = System.IO.Path.GetDirectoryName (asmFile);
 
189
                        
 
190
                        string customDir = Environment.GetEnvironmentVariable ("MONO_ADDINS_REGISTRY");
 
191
                        if (customDir != null && customDir.Length > 0)
 
192
                                configDir = customDir;
 
193
 
 
194
                        if (configDir == null || configDir.Length == 0)
 
195
                                registry = AddinRegistry.GetGlobalRegistry (this, startupDirectory);
 
196
                        else
 
197
                                registry = new AddinRegistry (this, configDir, startupDirectory, addinsDir, databaseDir);
 
198
 
 
199
                        if (registry.CreateHostAddinsFile (asmFile) || registry.UnknownDomain)
 
200
                                registry.Update (new ConsoleProgressStatus (false));
 
201
                        
 
202
                        initialized = true;
 
203
                        
 
204
                        ActivateRoots ();
 
205
                        OnAssemblyLoaded (null, null);
 
206
                        AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler (OnAssemblyLoaded);
 
207
                }
 
208
                
 
209
                /// <summary>
 
210
                /// Finalizes the add-in engine.
 
211
                /// </summary>
 
212
                public void Shutdown ()
 
213
                {
 
214
                        initialized = false;
 
215
                        AppDomain.CurrentDomain.AssemblyLoad -= new AssemblyLoadEventHandler (OnAssemblyLoaded);
 
216
                        loadedAddins.Clear ();
 
217
                        loadedAssemblies.Clear ();
 
218
                        registry.Dispose ();
 
219
                        registry = null;
 
220
                        startupDirectory = null;
 
221
                        ClearContext ();
 
222
                }
 
223
                
 
224
                /// <summary>
 
225
                /// Sets the default localizer to be used for this add-in engine
 
226
                /// </summary>
 
227
                /// <param name="localizer">
 
228
                /// The add-in localizer
 
229
                /// </param>
 
230
                public void InitializeDefaultLocalizer (IAddinLocalizer localizer)
 
231
                {
 
232
                        CheckInitialized ();
 
233
                        if (localizer != null)
 
234
                                defaultLocalizer = new AddinLocalizer (localizer);
 
235
                        else
 
236
                                defaultLocalizer = null;
 
237
                }
 
238
                
 
239
                internal string StartupDirectory {
 
240
                        get { return startupDirectory; }
 
241
                }
 
242
                
 
243
                /// <summary>
 
244
                /// Gets whether the add-in engine has been initialized.
 
245
                /// </summary>
 
246
                public bool IsInitialized {
 
247
                        get { return initialized; }
 
248
                }
 
249
                
 
250
                /// <summary>
 
251
                /// Gets the default add-in installer
 
252
                /// </summary>
 
253
                /// <remarks>
 
254
                /// The default installer is used by the CheckInstalled method to request
 
255
                /// the installation of missing add-ins.
 
256
                /// </remarks>
 
257
                public IAddinInstaller DefaultInstaller {
 
258
                        get { return installer; }
 
259
                        set { installer = value; }
 
260
                }
 
261
                
 
262
                /// <summary>
 
263
                /// Gets the default localizer for this add-in engine
 
264
                /// </summary>
 
265
                public AddinLocalizer DefaultLocalizer {
 
266
                        get {
 
267
                                CheckInitialized ();
 
268
                                if (defaultLocalizer != null)
 
269
                                        return defaultLocalizer; 
 
270
                                else
 
271
                                        return NullLocalizer.Instance;
 
272
                        }
 
273
                }
 
274
                
 
275
                internal ExtensionContext DefaultContext {
 
276
                        get { return this; }
 
277
                }
 
278
                
 
279
                /// <summary>
 
280
                /// Gets the localizer for the add-in that is invoking this property
 
281
                /// </summary>
 
282
                public AddinLocalizer CurrentLocalizer {
 
283
                        get {
 
284
                                CheckInitialized ();
 
285
                                Assembly asm = Assembly.GetCallingAssembly ();
 
286
                                RuntimeAddin addin = GetAddinForAssembly (asm);
 
287
                                if (addin != null)
 
288
                                        return addin.Localizer;
 
289
                                else
 
290
                                        return DefaultLocalizer;
 
291
                        }
 
292
                }
 
293
                
 
294
                /// <summary>
 
295
                /// Gets a reference to the RuntimeAddin object for the add-in that is invoking this property
 
296
                /// </summary>
 
297
                public RuntimeAddin CurrentAddin {
 
298
                        get {
 
299
                                CheckInitialized ();
 
300
                                Assembly asm = Assembly.GetCallingAssembly ();
 
301
                                return GetAddinForAssembly (asm);
 
302
                        }
 
303
                }
 
304
                
 
305
                /// <summary>
 
306
                /// Gets the add-in registry bound to this add-in engine
 
307
                /// </summary>
 
308
                public AddinRegistry Registry {
 
309
                        get {
 
310
                                CheckInitialized ();
 
311
                                return registry;
 
312
                        }
 
313
                }
 
314
                
 
315
                internal RuntimeAddin GetAddinForAssembly (Assembly asm)
 
316
                {
 
317
                        return (RuntimeAddin) loadedAssemblies [asm];
 
318
                }
 
319
                
 
320
                /// <summary>
 
321
                /// Checks if the provided add-ins are installed, and requests the installation of those
 
322
                /// which aren't.
 
323
                /// </summary>
 
324
                /// <param name="message">
 
325
                /// Message to show to the user when new add-ins have to be installed.
 
326
                /// </param>
 
327
                /// <param name="addinIds">
 
328
                /// List of IDs of the add-ins to be checked.
 
329
                /// </param>
 
330
                /// <remarks>
 
331
                /// This method checks if the specified add-ins are installed.
 
332
                /// If some of the add-ins are not installed, it will use
 
333
                /// the installer assigned to the DefaultAddinInstaller property
 
334
                /// to install them. If the installation fails, or if DefaultAddinInstaller
 
335
                /// is not set, an exception will be thrown.
 
336
                /// </remarks>
 
337
                public void CheckInstalled (string message, params string[] addinIds)
 
338
                {
 
339
                        ArrayList notInstalled = new ArrayList ();
 
340
                        foreach (string id in addinIds) {
 
341
                                Addin addin = Registry.GetAddin (id, false);
 
342
                                if (addin != null) {
 
343
                                        // The add-in is already installed
 
344
                                        // If the add-in is disabled, enable it now
 
345
                                        if (!addin.Enabled)
 
346
                                                addin.Enabled = true;
 
347
                                } else {
 
348
                                        notInstalled.Add (id);
 
349
                                }
 
350
                        }
 
351
                        if (notInstalled.Count == 0)
 
352
                                return;
 
353
                        if (installer == null)
 
354
                                throw new InvalidOperationException ("Add-in installer not set");
 
355
                        
 
356
                        // Install the add-ins
 
357
                        installer.InstallAddins (Registry, message, (string[]) notInstalled.ToArray (typeof(string)));
 
358
                }
 
359
                
 
360
                // Enables or disables conflict checking while loading assemblies.
 
361
                // Disabling makes loading faster, but less safe.
 
362
                internal bool CheckAssemblyLoadConflicts {
 
363
                        get { return checkAssemblyLoadConflicts; }
 
364
                        set { checkAssemblyLoadConflicts = value; }
 
365
                }
 
366
                
 
367
                /// <summary>
 
368
                /// Checks if an add-in has been loaded.
 
369
                /// </summary>
 
370
                /// <param name="id">
 
371
                /// Full identifier of the add-in.
 
372
                /// </param>
 
373
                /// <returns>
 
374
                /// True if the add-in is loaded.
 
375
                /// </returns>
 
376
                public bool IsAddinLoaded (string id)
 
377
                {
 
378
                        CheckInitialized ();
 
379
                        return loadedAddins.Contains (Addin.GetIdName (id));
 
380
                }
 
381
                
 
382
                internal RuntimeAddin GetAddin (string id)
 
383
                {
 
384
                        return (RuntimeAddin) loadedAddins [Addin.GetIdName (id)];
 
385
                }
 
386
                
 
387
                internal void ActivateAddin (string id)
 
388
                {
 
389
                        ActivateAddinExtensions (id);
 
390
                }
 
391
                
 
392
                internal void UnloadAddin (string id)
 
393
                {
 
394
                        RemoveAddinExtensions (id);
 
395
                        
 
396
                        RuntimeAddin addin = GetAddin (id);
 
397
                        if (addin != null) {
 
398
                                addin.UnloadExtensions ();
 
399
                                loadedAddins.Remove (Addin.GetIdName (id));
 
400
                                if (addin.AssembliesLoaded) {
 
401
                                        foreach (Assembly asm in addin.Assemblies)
 
402
                                                loadedAssemblies.Remove (asm);
 
403
                                }
 
404
                                ReportAddinUnload (id);
 
405
                        }
 
406
                }
 
407
                
 
408
                /// <summary>
 
409
                /// Forces the loading of an add-in.
 
410
                /// </summary>
 
411
                /// <param name="statusMonitor">
 
412
                /// Status monitor to keep track of the loading process.
 
413
                /// </param>
 
414
                /// <param name="id">
 
415
                /// Full identifier of the add-in to load.
 
416
                /// </param>
 
417
                /// <remarks>
 
418
                /// This method loads all assemblies that belong to an add-in in memory.
 
419
                /// All add-ins on which the specified add-in depends will also be loaded.
 
420
                /// Notice that in general add-ins don't need to be explicitely loaded using
 
421
                /// this method, since the add-in engine will load them on demand.
 
422
                /// </remarks>
 
423
                public void LoadAddin (IProgressStatus statusMonitor, string id)
 
424
                {
 
425
                        CheckInitialized ();
 
426
                        LoadAddin (statusMonitor, id, true);
 
427
                }
 
428
                
 
429
                internal bool LoadAddin (IProgressStatus statusMonitor, string id, bool throwExceptions)
 
430
                {
 
431
                        try {
 
432
                                if (IsAddinLoaded (id))
 
433
                                        return true;
 
434
 
 
435
                                if (!Registry.IsAddinEnabled (id)) {
 
436
                                        string msg = GettextCatalog.GetString ("Disabled add-ins can't be loaded.");
 
437
                                        ReportError (msg, id, null, false);
 
438
                                        if (throwExceptions)
 
439
                                                throw new InvalidOperationException (msg);
 
440
                                        return false;
 
441
                                }
 
442
 
 
443
                                ArrayList addins = new ArrayList ();
 
444
                                Stack depCheck = new Stack ();
 
445
                                ResolveLoadDependencies (addins, depCheck, id, false);
 
446
                                addins.Reverse ();
 
447
                                
 
448
                                if (statusMonitor != null)
 
449
                                        statusMonitor.SetMessage ("Loading Addins");
 
450
                                
 
451
                                for (int n=0; n<addins.Count; n++) {
 
452
                                        
 
453
                                        if (statusMonitor != null)
 
454
                                                statusMonitor.SetProgress ((double) n / (double)addins.Count);
 
455
                                        
 
456
                                        Addin iad = (Addin) addins [n];
 
457
                                        if (IsAddinLoaded (iad.Id))
 
458
                                                continue;
 
459
 
 
460
                                        if (statusMonitor != null)
 
461
                                                statusMonitor.SetMessage (string.Format(GettextCatalog.GetString("Loading {0} add-in"), iad.Id));
 
462
                                        
 
463
                                        if (!InsertAddin (statusMonitor, iad))
 
464
                                                return false;
 
465
                                }
 
466
                                return true;
 
467
                        }
 
468
                        catch (Exception ex) {
 
469
                                ReportError ("Add-in could not be loaded: " + ex.Message, id, ex, false);
 
470
                                if (statusMonitor != null)
 
471
                                        statusMonitor.ReportError ("Add-in '" + id + "' could not be loaded.", ex);
 
472
                                if (throwExceptions)
 
473
                                        throw;
 
474
                                return false;
 
475
                        }
 
476
                }
 
477
 
 
478
                internal override void ResetCachedData ()
 
479
                {
 
480
                        foreach (RuntimeAddin ad in loadedAddins.Values)
 
481
                                ad.Addin.ResetCachedData ();
 
482
                        base.ResetCachedData ();
 
483
                }
 
484
                        
 
485
                bool InsertAddin (IProgressStatus statusMonitor, Addin iad)
 
486
                {
 
487
                        try {
 
488
                                RuntimeAddin p = new RuntimeAddin (this);
 
489
                                
 
490
                                // Read the config file and load the add-in assemblies
 
491
                                AddinDescription description = p.Load (iad);
 
492
                                
 
493
                                // Register the add-in
 
494
                                loadedAddins [Addin.GetIdName (p.Id)] = p;
 
495
                                
 
496
                                if (!AddinDatabase.RunningSetupProcess) {
 
497
                                        // Load the extension points and other addin data
 
498
                                        
 
499
                                        foreach (ExtensionNodeSet rel in description.ExtensionNodeSets) {
 
500
                                                RegisterNodeSet (iad.Id, rel);
 
501
                                        }
 
502
                                        
 
503
                                        foreach (ConditionTypeDescription cond in description.ConditionTypes) {
 
504
                                                Type ctype = p.GetType (cond.TypeName, true);
 
505
                                                RegisterCondition (cond.Id, ctype);
 
506
                                        }
 
507
                                }
 
508
                                        
 
509
                                foreach (ExtensionPoint ep in description.ExtensionPoints)
 
510
                                        InsertExtensionPoint (p, ep);
 
511
                                
 
512
                                // Fire loaded event
 
513
                                NotifyAddinLoaded (p);
 
514
                                ReportAddinLoad (p.Id);
 
515
                                return true;
 
516
                        }
 
517
                        catch (Exception ex) {
 
518
                                ReportError ("Add-in could not be loaded", iad.Id, ex, false);
 
519
                                if (statusMonitor != null)
 
520
                                        statusMonitor.ReportError ("Add-in '" + iad.Id + "' could not be loaded.", ex);
 
521
                                return false;
 
522
                        }
 
523
                }
 
524
                
 
525
                internal void RegisterAssemblies (RuntimeAddin addin)
 
526
                {
 
527
                        foreach (Assembly asm in addin.Assemblies)
 
528
                                loadedAssemblies [asm] = addin;
 
529
                }
 
530
                
 
531
                internal void InsertExtensionPoint (RuntimeAddin addin, ExtensionPoint ep)
 
532
                {
 
533
                        CreateExtensionPoint (ep);
 
534
                        foreach (ExtensionNodeType nt in ep.NodeSet.NodeTypes) {
 
535
                                if (nt.ObjectTypeName.Length > 0) {
 
536
                                        Type ntype = addin.GetType (nt.ObjectTypeName, true);
 
537
                                        RegisterAutoTypeExtensionPoint (ntype, ep.Path);
 
538
                                }
 
539
                        }
 
540
                }
 
541
                
 
542
                bool ResolveLoadDependencies (ArrayList addins, Stack depCheck, string id, bool optional)
 
543
                {
 
544
                        if (IsAddinLoaded (id))
 
545
                                return true;
 
546
                                
 
547
                        if (depCheck.Contains (id))
 
548
                                throw new InvalidOperationException ("A cyclic addin dependency has been detected.");
 
549
 
 
550
                        depCheck.Push (id);
 
551
 
 
552
                        Addin iad = Registry.GetAddin (id);
 
553
                        if (iad == null || !iad.Enabled) {
 
554
                                if (optional)
 
555
                                        return false;
 
556
                                else if (iad != null && !iad.Enabled)
 
557
                                        throw new MissingDependencyException (GettextCatalog.GetString ("The required addin '{0}' is disabled.", id));
 
558
                                else
 
559
                                        throw new MissingDependencyException (GettextCatalog.GetString ("The required addin '{0}' is not installed.", id));
 
560
                        }
 
561
 
 
562
                        // If this addin has already been requested, bring it to the head
 
563
                        // of the list, so it is loaded earlier than before.
 
564
                        addins.Remove (iad);
 
565
                        addins.Add (iad);
 
566
                        
 
567
                        foreach (Dependency dep in iad.AddinInfo.Dependencies) {
 
568
                                AddinDependency adep = dep as AddinDependency;
 
569
                                if (adep != null) {
 
570
                                        try {
 
571
                                                string adepid = Addin.GetFullId (iad.AddinInfo.Namespace, adep.AddinId, adep.Version);
 
572
                                                ResolveLoadDependencies (addins, depCheck, adepid, false);
 
573
                                        } catch (MissingDependencyException) {
 
574
                                                if (optional)
 
575
                                                        return false;
 
576
                                                else
 
577
                                                        throw;
 
578
                                        }
 
579
                                }
 
580
                        }
 
581
                        
 
582
                        if (iad.AddinInfo.OptionalDependencies != null) {
 
583
                                foreach (Dependency dep in iad.AddinInfo.OptionalDependencies) {
 
584
                                        AddinDependency adep = dep as AddinDependency;
 
585
                                        if (adep != null) {
 
586
                                                string adepid = Addin.GetFullId (iad.Namespace, adep.AddinId, adep.Version);
 
587
                                                if (!ResolveLoadDependencies (addins, depCheck, adepid, true))
 
588
                                                return false;
 
589
                                        }
 
590
                                }
 
591
                        }
 
592
                                
 
593
                        depCheck.Pop ();
 
594
                        return true;
 
595
                }
 
596
                
 
597
                internal void RegisterNodeSet (string addinId, ExtensionNodeSet nset)
 
598
                {
 
599
                        nset.SourceAddinId = addinId;
 
600
                        nodeSets [nset.Id] = nset;
 
601
                }
 
602
                
 
603
                internal void UnregisterAddinNodeSets (string addinId)
 
604
                {
 
605
                        foreach (var nset in nodeSets.Values.Where (n => n.SourceAddinId == addinId).ToArray ())
 
606
                                nodeSets.Remove (nset.Id);
 
607
                }
 
608
                
 
609
                internal string GetNodeTypeAddin (ExtensionNodeSet nset, string type, string callingAddinId)
 
610
                {
 
611
                        ExtensionNodeType nt = FindType (nset, type, callingAddinId);
 
612
                        if (nt != null)
 
613
                                return nt.AddinId;
 
614
                        else
 
615
                                return null;
 
616
                }
 
617
                
 
618
                internal ExtensionNodeType FindType (ExtensionNodeSet nset, string name, string callingAddinId)
 
619
                {
 
620
                        if (nset == null)
 
621
                                return null;
 
622
 
 
623
                        foreach (ExtensionNodeType nt in nset.NodeTypes) {
 
624
                                if (nt.Id == name)
 
625
                                        return nt;
 
626
                        }
 
627
                        
 
628
                        foreach (string ns in nset.NodeSets) {
 
629
                                ExtensionNodeSet regSet;
 
630
                                if (!nodeSets.TryGetValue (ns, out regSet)) {
 
631
                                        ReportError ("Unknown node set: " + ns, callingAddinId, null, false);
 
632
                                        return null;
 
633
                                }
 
634
                                ExtensionNodeType nt = FindType (regSet, name, callingAddinId);
 
635
                                if (nt != null)
 
636
                                        return nt;
 
637
                        }
 
638
                        return null;
 
639
                }
 
640
                
 
641
                internal void RegisterAutoTypeExtensionPoint (Type type, string path)
 
642
                {
 
643
                        autoExtensionTypes [type] = path;
 
644
                }
 
645
 
 
646
                internal void UnregisterAutoTypeExtensionPoint (Type type, string path)
 
647
                {
 
648
                        autoExtensionTypes.Remove (type);
 
649
                }
 
650
                
 
651
                internal string GetAutoTypeExtensionPoint (Type type)
 
652
                {
 
653
                        return autoExtensionTypes [type] as string;
 
654
                }
 
655
 
 
656
                void OnAssemblyLoaded (object s, AssemblyLoadEventArgs a)
 
657
                {
 
658
                        if (a != null)
 
659
                                CheckHostAssembly (a.LoadedAssembly);
 
660
                }
 
661
                
 
662
                internal void ActivateRoots ()
 
663
                {
 
664
                        foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies ())
 
665
                                CheckHostAssembly (asm);
 
666
                }
 
667
                
 
668
                void CheckHostAssembly (Assembly asm)
 
669
                {
 
670
                        if (AddinDatabase.RunningSetupProcess || asm is System.Reflection.Emit.AssemblyBuilder || asm.IsDynamic)
 
671
                                return;
 
672
                        string codeBase;
 
673
                        try {
 
674
                                codeBase = asm.CodeBase;
 
675
                        } catch {
 
676
                                return;
 
677
                        }
 
678
                        Uri u;
 
679
                        if (!Uri.TryCreate (codeBase, UriKind.Absolute, out u))
 
680
                                return;
 
681
                        string asmFile = u.LocalPath;
 
682
                        Addin ainfo = Registry.GetAddinForHostAssembly (asmFile);
 
683
                        if (ainfo != null && !IsAddinLoaded (ainfo.Id)) {
 
684
                                AddinDescription adesc = null;
 
685
                                try {
 
686
                                        adesc = ainfo.Description;
 
687
                                } catch (Exception ex) {
 
688
                                        defaultProgressStatus.ReportError ("Add-in description could not be loaded.", ex);
 
689
                                }
 
690
                                if (adesc == null || adesc.FilesChanged ()) {
 
691
                                        // If the add-in has changed, update the add-in database.
 
692
                                        // We do it here because once loaded, add-in roots can't be
 
693
                                        // reloaded like regular add-ins.
 
694
                                        Registry.Update (null);
 
695
                                        ainfo = Registry.GetAddinForHostAssembly (asmFile);
 
696
                                        if (ainfo == null)
 
697
                                                return;
 
698
                                }
 
699
                                LoadAddin (null, ainfo.Id, false);
 
700
                        }
 
701
                }
 
702
                
 
703
                /// <summary>
 
704
                /// Creates a new extension context.
 
705
                /// </summary>
 
706
                /// <returns>
 
707
                /// The new extension context.
 
708
                /// </returns>
 
709
                /// <remarks>
 
710
                /// Extension contexts can be used to query the extension model using particular condition values.
 
711
                /// </remarks>
 
712
                public ExtensionContext CreateExtensionContext ()
 
713
                {
 
714
                        CheckInitialized ();
 
715
                        return CreateChildContext ();
 
716
                }
 
717
                
 
718
                internal void CheckInitialized ()
 
719
                {
 
720
                        if (!initialized)
 
721
                                throw new InvalidOperationException ("Add-in engine not initialized.");
 
722
                }
 
723
                
 
724
                internal void ReportError (string message, string addinId, Exception exception, bool fatal)
 
725
                {
 
726
                        if (AddinLoadError != null)
 
727
                                AddinLoadError (null, new AddinErrorEventArgs (message, addinId, exception));
 
728
                        else {
 
729
                                Console.WriteLine (message);
 
730
                                if (exception != null)
 
731
                                        Console.WriteLine (exception);
 
732
                        }
 
733
                }
 
734
                
 
735
                internal void ReportAddinLoad (string id)
 
736
                {
 
737
                        if (AddinLoaded != null) {
 
738
                                try {
 
739
                                        AddinLoaded (null, new AddinEventArgs (id));
 
740
                                } catch {
 
741
                                        // Ignore subscriber exceptions
 
742
                                }
 
743
                        }
 
744
                }
 
745
                
 
746
                internal void ReportAddinUnload (string id)
 
747
                {
 
748
                        if (AddinUnloaded != null) {
 
749
                                try {
 
750
                                        AddinUnloaded (null, new AddinEventArgs (id));
 
751
                                } catch {
 
752
                                        // Ignore subscriber exceptions
 
753
                                }
 
754
                        }
 
755
                }
 
756
        }
 
757
                
 
758
}