Merge remote-tracking branch 'github/master'
[mono.git] / mcs / class / System / System.ComponentModel.Design / ServiceContainer.cs
1 //
2 // System.ComponentModel.Design.ServiceContainer.cs
3 //
4 // Authors:
5 //   Martin Willemoes Hansen (mwh@sysrq.dk)
6 //   Andreas Nahr (ClassDevelopment@A-SoftTech.com)
7 //   Ivan N. Zlatev (contact i-nZ.net)
8 //
9 // (C) 2003 Martin Willemoes Hansen
10 // (C) 2003 Andreas Nahr
11 // (C) 2006 Ivan N. Zlatev
12
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33
34 using System;
35 using System.Collections;
36
37 namespace System.ComponentModel.Design
38 {
39         public class ServiceContainer : IServiceContainer, IServiceProvider, IDisposable
40         {
41                 private IServiceProvider parentProvider;
42                 private Hashtable services;
43                 private bool _disposed;
44                 
45                 public ServiceContainer()
46                         : this (null)
47                 {
48                 }
49
50                 private Hashtable Services {
51                         get {
52                                 if (services == null)
53                                         services = new Hashtable ();
54                                 return services;
55                         }
56                 }
57
58                 public ServiceContainer (IServiceProvider parentProvider)
59                 {
60                         this.parentProvider = parentProvider;
61                 }
62
63                 public void AddService (Type serviceType, object serviceInstance)
64                 {
65                         AddService (serviceType, serviceInstance, false);
66                 }
67
68                 public void AddService (Type serviceType, ServiceCreatorCallback callback)
69                 {
70                         AddService (serviceType, callback, false);
71                 }
72
73                 public virtual void AddService (Type serviceType,
74                                         object serviceInstance,
75                                         bool promote)
76                 {
77                         if (promote && parentProvider != null) {
78                                 IServiceContainer container = (IServiceContainer)
79                                         parentProvider.GetService (typeof (IServiceContainer));
80                                 container.AddService (serviceType, serviceInstance, promote);
81                                 return;
82                         }
83
84                         if (serviceType == null)
85                                 throw new ArgumentNullException ("serviceType");
86                         if (serviceInstance == null)
87                                 throw new ArgumentNullException ("serviceInstance");
88                         if (Services.Contains (serviceType))
89                                 throw new ArgumentException (string.Format (
90                                         "The service {0} already exists in the service container.",
91                                         serviceType.ToString ()), "serviceType");
92                         Services.Add (serviceType, serviceInstance);
93                 }
94
95                 public virtual
96                 void AddService (Type serviceType,
97                                         ServiceCreatorCallback callback,
98                                         bool promote)
99                 {
100                         if (promote && parentProvider != null) {
101                                 IServiceContainer container = (IServiceContainer)
102                                         parentProvider.GetService (typeof (IServiceContainer));
103                                 container.AddService (serviceType, callback, promote);
104                                 return;
105                         }
106
107                         if (serviceType == null)
108                                 throw new ArgumentNullException ("serviceType");
109                         if (callback == null)
110                                 throw new ArgumentNullException ("callback");
111                         if (Services.Contains (serviceType))
112                                 throw new ArgumentException (string.Format (
113                                         "The service {0} already exists in the service container.",
114                                         serviceType.ToString ()), "serviceType");
115                         Services.Add (serviceType, callback);
116                 }
117
118                 public void RemoveService (Type serviceType)
119                 {
120                         RemoveService (serviceType, false);
121                 }
122
123                 public virtual void RemoveService (Type serviceType, bool promote)
124                 {
125                         if (promote && parentProvider != null) {
126                                 IServiceContainer container = (IServiceContainer)
127                                         parentProvider.GetService (typeof (IServiceContainer));
128                                 container.RemoveService (serviceType, promote);
129                                 return;
130                         }
131
132                         if (serviceType == null)
133                                 throw new ArgumentNullException ("serviceType");
134                         Services.Remove (serviceType);
135                 }
136
137                 public virtual
138                 object GetService (Type serviceType)
139                 {
140                         object result = null;
141
142                         Type[] defaultServices = this.DefaultServices;
143                         for (int i=0; i < defaultServices.Length; i++) {
144                                 if (defaultServices[i] == serviceType) {
145                                         result = this;
146                                         break;
147                                 }
148                         }
149
150                         if (result == null)
151                                 result = Services [serviceType];
152                         if (result == null && parentProvider != null)
153                                 result = parentProvider.GetService (serviceType);
154                         if (result != null) {
155                                 ServiceCreatorCallback cb = result as ServiceCreatorCallback;
156                                 if (cb != null) {
157                                         result = cb (this, serviceType);
158                                         Services [serviceType] = result;
159                                 }
160                         }
161                         return result;
162                 }
163
164                 protected virtual
165                 Type [] DefaultServices {
166                         get {
167                                 return new Type [] { typeof (IServiceContainer), typeof (ServiceContainer)};
168                         }
169                 }
170
171                 public void Dispose ()
172                 {
173                         this.Dispose (true);
174                         GC.SuppressFinalize (this);
175                 }
176
177                 protected virtual void Dispose (bool disposing)
178                 {
179                         if (!_disposed) {
180                                 if (disposing) {
181                                         if (services != null) {
182                                                 foreach (object obj in services) {
183                                                         if (obj is IDisposable) {
184                                                                 ((IDisposable) obj).Dispose ();
185                                                         }
186                                                 }
187                                                 services = null;
188                                         }
189                                 }
190                                 _disposed = true;
191                         }
192                 }
193         }
194 }