7
// Copyright (C) 2007 Novell, Inc (http://www.novell.com)
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:
17
// The above copyright notice and this permission notice shall be
18
// included in all copies or substantial portions of the Software.
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.
31
using System.Collections;
32
using Mono.Addins.Description;
34
namespace Mono.Addins.Database
38
// This table collects information about extensions. For each path (key)
39
// has a ExtensionInfo object with information about the addin that
40
// defines the extension point and the addins which extend it
41
Hashtable pathHash = new Hashtable ();
43
// Collects globally defined node sets. Key is node set name. Value is
45
Hashtable nodeSetHash = new Hashtable ();
47
Hashtable objectTypeExtensions = new Hashtable ();
49
internal int RelExtensionPoints;
50
internal int RelExtensions;
51
internal int RelNodeSetTypes;
52
internal int RelExtensionNodes;
54
class RootExtensionPoint
56
public AddinDescription Description;
57
public ExtensionPoint ExtensionPoint;
60
IProgressStatus monitor;
62
public AddinUpdateData (AddinDatabase database, IProgressStatus monitor)
64
this.monitor = monitor;
67
public void RegisterNodeSet (AddinDescription description, ExtensionNodeSet nset)
69
ArrayList extensions = (ArrayList) nodeSetHash [nset.Id];
70
if (extensions != null) {
71
// Extension point already registered
72
ArrayList compatExtensions = GetCompatibleExtensionPoints (nset.Id, description, description.MainModule, extensions);
73
if (compatExtensions.Count > 0) {
74
foreach (ExtensionPoint einfo in compatExtensions)
75
einfo.NodeSet.MergeWith (null, nset);
79
// Create a new extension set
80
RootExtensionPoint rep = new RootExtensionPoint ();
81
rep.ExtensionPoint = new ExtensionPoint ();
82
rep.ExtensionPoint.SetNodeSet (nset);
83
rep.ExtensionPoint.RootAddin = description.AddinId;
84
rep.ExtensionPoint.Path = nset.Id;
85
rep.Description = description;
86
if (extensions == null) {
87
extensions = new ArrayList ();
88
nodeSetHash [nset.Id] = extensions;
93
public void RegisterExtensionPoint (AddinDescription description, ExtensionPoint ep)
95
ArrayList extensions = (ArrayList) pathHash [ep.Path];
96
if (extensions != null) {
97
// Extension point already registered
98
ArrayList compatExtensions = GetCompatibleExtensionPoints (ep.Path, description, description.MainModule, extensions);
99
if (compatExtensions.Count > 0) {
100
foreach (ExtensionPoint einfo in compatExtensions)
101
einfo.MergeWith (null, ep);
102
RegisterObjectTypes (ep);
106
// Create a new extension
107
RootExtensionPoint rep = new RootExtensionPoint ();
108
rep.ExtensionPoint = ep;
109
rep.ExtensionPoint.RootAddin = description.AddinId;
110
rep.Description = description;
111
if (extensions == null) {
112
extensions = new ArrayList ();
113
pathHash [ep.Path] = extensions;
115
extensions.Add (rep);
116
RegisterObjectTypes (ep);
119
void RegisterObjectTypes (ExtensionPoint ep)
121
// Register extension points bound to a node type
123
foreach (ExtensionNodeType nt in ep.NodeSet.NodeTypes) {
124
if (nt.ObjectTypeName.Length > 0) {
125
ArrayList list = (ArrayList) objectTypeExtensions [nt.ObjectTypeName];
127
list = new ArrayList ();
128
objectTypeExtensions [nt.ObjectTypeName] = list;
135
public void RegisterExtension (AddinDescription description, ModuleDescription module, Extension extension)
137
if (extension.Path.StartsWith ("$")) {
138
string[] objectTypes = extension.Path.Substring (1).Split (',');
140
foreach (string s in objectTypes) {
141
ArrayList list = (ArrayList) objectTypeExtensions [s];
144
foreach (ExtensionPoint ep in list) {
145
if (IsAddinCompatible (ep.ParentAddinDescription, description, module)) {
146
extension.Path = ep.Path;
147
RegisterExtension (description, module, ep.Path);
153
monitor.ReportWarning ("The add-in '" + description.AddinId + "' is trying to register the class '" + extension.Path.Substring (1) + "', but there isn't any add-in defining a suitable extension point");
157
public void RegisterExtension (AddinDescription description, ModuleDescription module, string path)
159
ArrayList extensions = (ArrayList) pathHash [path];
160
if (extensions == null) {
161
// Root add-in extension points are registered before any other kind of extension,
162
// so we should find it now.
163
extensions = GetParentExtensionInfo (path);
165
if (extensions == null) {
166
monitor.ReportWarning ("The add-in '" + description.AddinId + "' is trying to extend '" + path + "', but there isn't any add-in defining this extension point");
171
foreach (RootExtensionPoint einfo in extensions) {
172
if (IsAddinCompatible (einfo.Description, description, module)) {
173
if (!einfo.ExtensionPoint.Addins.Contains (description.AddinId))
174
einfo.ExtensionPoint.Addins.Add (description.AddinId);
179
monitor.ReportWarning ("The add-in '" + description.AddinId + "' is trying to extend '" + path + "', but there isn't any compatible add-in defining this extension point");
182
ArrayList GetCompatibleExtensionPoints (string path, AddinDescription description, ModuleDescription module, ArrayList rootExtensionPoints)
184
ArrayList list = new ArrayList ();
185
foreach (RootExtensionPoint rep in rootExtensionPoints) {
187
// Find an extension point defined in a root add-in which is compatible with the version of the extender dependency
188
if (IsAddinCompatible (rep.Description, description, module))
189
list.Add (rep.ExtensionPoint);
194
ArrayList GetParentExtensionInfo (string path)
196
int i = path.LastIndexOf ('/');
199
string np = path.Substring (0, i);
200
ArrayList ep = (ArrayList) pathHash [np];
204
return GetParentExtensionInfo (np);
207
bool IsAddinCompatible (AddinDescription installedDescription, AddinDescription description, ModuleDescription module)
209
if (installedDescription == description)
211
if (installedDescription.Domain != AddinDatabase.GlobalDomain) {
212
if (description.Domain != AddinDatabase.GlobalDomain && description.Domain != installedDescription.Domain)
214
} else if (description.Domain != AddinDatabase.GlobalDomain)
217
string addinId = Addin.GetFullId (installedDescription.Namespace, installedDescription.LocalId, null);
218
string requiredVersion = null;
220
for (int n = module.Dependencies.Count - 1; n >= 0; n--) {
221
AddinDependency adep = module.Dependencies [n] as AddinDependency;
222
if (adep != null && Addin.GetFullId (description.Namespace, adep.AddinId, null) == addinId) {
223
requiredVersion = adep.Version;
227
if (requiredVersion == null)
230
// Check if the required version is between rep.Description.CompatVersion and rep.Description.Version
231
if (Addin.CompareVersions (installedDescription.Version, requiredVersion) > 0)
233
if (installedDescription.CompatVersion.Length > 0 && Addin.CompareVersions (installedDescription.CompatVersion, requiredVersion) < 0)