Lines 10-23
Link Here
|
10 |
*******************************************************************************/ |
10 |
*******************************************************************************/ |
11 |
package org.eclipse.cdt.dsf.service; |
11 |
package org.eclipse.cdt.dsf.service; |
12 |
|
12 |
|
13 |
import java.util.Arrays; |
|
|
14 |
import java.util.Dictionary; |
13 |
import java.util.Dictionary; |
15 |
import java.util.Enumeration; |
14 |
import java.util.Enumeration; |
16 |
import java.util.HashSet; |
15 |
import java.util.Hashtable; |
17 |
import java.util.Set; |
16 |
import java.util.List; |
18 |
|
17 |
|
19 |
import org.eclipse.cdt.dsf.concurrent.DsfExecutor; |
18 |
import org.eclipse.cdt.dsf.concurrent.DsfExecutor; |
20 |
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; |
19 |
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants; |
|
|
20 |
import org.eclipse.cdt.dsf.concurrent.ImmediateExecutor; |
21 |
import org.eclipse.cdt.dsf.concurrent.RequestMonitor; |
21 |
import org.eclipse.cdt.dsf.concurrent.RequestMonitor; |
22 |
import org.osgi.framework.BundleContext; |
22 |
import org.osgi.framework.BundleContext; |
23 |
import org.osgi.framework.Constants; |
23 |
import org.osgi.framework.Constants; |
Lines 65-71
Link Here
|
65 |
public DsfExecutor getExecutor() { return fSession.getExecutor(); } |
65 |
public DsfExecutor getExecutor() { return fSession.getExecutor(); } |
66 |
|
66 |
|
67 |
/** |
67 |
/** |
68 |
* The the returned collection is a superset of the properties specified in |
68 |
* The returned collection is a superset of the properties specified in |
69 |
* {@link #register(String[], Dictionary)}. That method can add additional |
69 |
* {@link #register(String[], Dictionary)}. That method can add additional |
70 |
* (implicit) properties. For one, it tacks on the |
70 |
* (implicit) properties. For one, it tacks on the |
71 |
* {@link Constants#OBJECTCLASS} property associated with the service after |
71 |
* {@link Constants#OBJECTCLASS} property associated with the service after |
Lines 81-98
Link Here
|
81 |
|
81 |
|
82 |
public int getStartupNumber() { return fStartupNumber; } |
82 |
public int getStartupNumber() { return fStartupNumber; } |
83 |
|
83 |
|
84 |
public void initialize(RequestMonitor rm) { |
84 |
/** |
|
|
85 |
* @return The class names under which the service can be located. For |
86 |
* convenience, [classes] need not contain {@link IDsfService}, |
87 |
* it is automatically added if not present. The complete list |
88 |
* of classes the service ends up being registered in OSGi with |
89 |
* is recorded and made available via |
90 |
* <code>getProperties().get(Constants.OBJECTCLASS)</code> |
91 |
*/ |
92 |
abstract protected List<String> getClassNamesToRegister(); |
93 |
|
94 |
/** |
95 |
* Sub-classes can override this method to specify properties to use for |
96 |
* the registration of the service, or to obtain directly the final |
97 |
* list of properties that was used to register the service. |
98 |
* |
99 |
* @return The properties for this service. The keys in the properties |
100 |
* object must all be <code>String</code> objects. See |
101 |
* {@link Constants} for a list of standard service property |
102 |
* keys. To update the service's properties after initialization |
103 |
* the {@link ServiceRegistration#setProperties} method must be |
104 |
* called. Caller should, at a minimum, pass an empty |
105 |
* dictionary--never null. We add a property to the collection |
106 |
* (we modify the list returned by this method), to record the id of |
107 |
* the dsf session associated with the service as well as all the names |
108 |
* of the classes the service ends up being registered in OSGi with. |
109 |
*/ |
110 |
@SuppressWarnings("rawtypes") |
111 |
protected Dictionary getPropertiesToRegister() { |
112 |
return new Hashtable<String, String>(); |
113 |
} |
114 |
|
115 |
final public void initialize(final RequestMonitor rm) { |
85 |
fTracker = new DsfServicesTracker(getBundleContext(), fSession.getId()); |
116 |
fTracker = new DsfServicesTracker(getBundleContext(), fSession.getId()); |
86 |
fStartupNumber = fSession.getAndIncrementServiceStartupCounter(); |
117 |
fStartupNumber = fSession.getAndIncrementServiceStartupCounter(); |
|
|
118 |
performInitialization( |
119 |
new RequestMonitor(ImmediateExecutor.getInstance(), rm) { |
120 |
@Override |
121 |
protected void handleSuccess() { |
122 |
if (getClassNamesToRegister() != null) { |
123 |
// Once all the initialization has been performed, we need to register |
124 |
// the service to make it available to be used. |
125 |
register(getClassNamesToRegister(), getPropertiesToRegister()); |
126 |
} |
127 |
rm.done(); |
128 |
}}); |
129 |
} |
130 |
|
131 |
/** @since 2.2 */ |
132 |
protected void performInitialization(RequestMonitor rm) { |
87 |
rm.done(); |
133 |
rm.done(); |
88 |
} |
134 |
} |
89 |
|
135 |
|
90 |
public void shutdown(RequestMonitor rm) { |
136 |
final public void shutdown(RequestMonitor rm) { |
91 |
fTracker.dispose(); |
137 |
unregister(); |
92 |
fTracker = null; |
138 |
performShutdown(rm); |
|
|
139 |
} |
140 |
|
141 |
/** @since 2.2 */ |
142 |
protected void performShutdown(RequestMonitor rm) { |
143 |
fTracker.dispose(); |
144 |
fTracker = null; |
93 |
rm.done(); |
145 |
rm.done(); |
94 |
} |
146 |
} |
95 |
|
147 |
|
96 |
/** |
148 |
/** |
97 |
* @since 2.0 |
149 |
* @since 2.0 |
98 |
*/ |
150 |
*/ |
Lines 117-126
Link Here
|
117 |
* |
169 |
* |
118 |
* @param classes |
170 |
* @param classes |
119 |
* The class names under which the service can be located. For |
171 |
* The class names under which the service can be located. For |
120 |
* convenience, [classes] need not contain {@link IDsfService} or |
172 |
* convenience, [classes] need not contain {@link IDsfService} |
121 |
* the runtime class of this object; they are automatically added |
173 |
* TODO or the runtime class of this object; they are automatically added |
122 |
* if not present. The complete list of classes the service ends |
174 |
* if not present (we modify the caller's object). |
123 |
* up being registered in OSGi with is recorded and made |
175 |
* The complete list of classes the service ends |
|
|
176 |
* up being registered in OSGi with is recorded and also made |
124 |
* available via |
177 |
* available via |
125 |
* <code>getProperties().get(Constants.OBJECTCLASS)</code> |
178 |
* <code>getProperties().get(Constants.OBJECTCLASS)</code> |
126 |
* @param properties |
179 |
* @param properties |
Lines 136-187
Link Here
|
136 |
* session associated with the service. |
189 |
* session associated with the service. |
137 |
*/ |
190 |
*/ |
138 |
@SuppressWarnings({ "rawtypes", "unchecked" }) |
191 |
@SuppressWarnings({ "rawtypes", "unchecked" }) |
139 |
protected void register(String[] classes, Dictionary properties) { |
192 |
private void register(List<String> classes, Dictionary properties) { |
|
|
193 |
assert fRegistration == null; |
140 |
|
194 |
|
141 |
/* |
|
|
142 |
* If this service has already been registered, make sure we |
143 |
* keep the names it has been registered with. However, we |
144 |
* must trigger a new registration or else OSGI will keep the two |
145 |
* registration separate. |
146 |
*/ |
147 |
if (fRegistration != null) { |
148 |
String[] previousClasses = (String[])fRegistration.getReference().getProperty(Constants.OBJECTCLASS); |
149 |
|
150 |
// Use a HashSet to avoid duplicates |
151 |
Set<String> newClasses = new HashSet<String>(); |
152 |
newClasses.addAll(Arrays.asList(previousClasses)); |
153 |
newClasses.addAll(Arrays.asList(classes)); |
154 |
classes = newClasses.toArray(new String[0]); |
155 |
|
156 |
/* |
157 |
* Also keep all previous properties. |
158 |
*/ |
159 |
if (fProperties != null) { |
160 |
for (Enumeration e = fProperties.keys() ; e.hasMoreElements();) { |
161 |
Object key = e.nextElement(); |
162 |
Object value = fProperties.get(key); |
163 |
properties.put(key, value); |
164 |
} |
165 |
} |
166 |
|
167 |
// Now, cancel the previous registration |
168 |
unregister(); |
169 |
} |
170 |
/* |
195 |
/* |
171 |
* Ensure that the list of classes contains the base DSF service |
196 |
* Ensure that the list of classes contains the base DSF service interface. |
172 |
* interface, as well as the actual class type of this object. |
|
|
173 |
*/ |
197 |
*/ |
174 |
if (!Arrays.asList(classes).contains(IDsfService.class.getName())) { |
198 |
if (!classes.contains(IDsfService.class.getName())) { |
175 |
String[] newClasses = new String[classes.length + 1]; |
199 |
classes.add(0, IDsfService.class.getName()); |
176 |
System.arraycopy(classes, 0, newClasses, 1, classes.length); |
|
|
177 |
newClasses[0] = IDsfService.class.getName(); |
178 |
classes = newClasses; |
179 |
} |
200 |
} |
180 |
if (!Arrays.asList(classes).contains(getClass().getName())) { |
201 |
|
181 |
String[] newClasses = new String[classes.length + 1]; |
202 |
/* |
182 |
System.arraycopy(classes, 0, newClasses, 1, classes.length); |
203 |
TODO |
183 |
newClasses[0] = getClass().getName(); |
204 |
I think we should remove this, although it may cause problems to existing extenders. |
184 |
classes = newClasses; |
205 |
|
|
|
206 |
The reason is that with the new getClassNamesToRegiter() method, I can see someone doing |
207 |
something like this |
208 |
|
209 |
BaseClass { |
210 |
protected List<String> getClassNamesToRegiter() { |
211 |
return new ArrayList<String>(); |
212 |
// Here the designer did not explicitly add |
213 |
// BaseClass.class.getName() to the list of names to register |
214 |
// because he relied on AbstractDsfService.register() to add |
215 |
// it automatically. |
216 |
} |
217 |
}; |
218 |
|
219 |
DerivedClass extends baseClass { |
220 |
protected List<String> getClassNamesToRegiter() { |
221 |
List<String> classes = super.getClassNamesToRegiter(); |
222 |
|
223 |
// PROBLEM, classes does not contain BaseClass.class.getName() |
224 |
// and AbstractDsfService.register() won't add it! |
225 |
|
226 |
classes.add(DerivedClass.class.getName()); |
227 |
return classes; |
228 |
} |
229 |
}; |
230 |
*/ |
231 |
/* |
232 |
* Ensure that the list of classes contains the actual class type of this object. |
233 |
*/ |
234 |
if (!classes.contains(getClass().getName())) { |
235 |
classes.add(0, getClass().getName()); |
185 |
} |
236 |
} |
186 |
/* |
237 |
/* |
187 |
* Make sure that the session ID is set in the service properties. |
238 |
* Make sure that the session ID is set in the service properties. |
Lines 190-196
Link Here
|
190 |
*/ |
241 |
*/ |
191 |
properties.put(PROP_SESSION_ID, getSession().getId()); |
242 |
properties.put(PROP_SESSION_ID, getSession().getId()); |
192 |
fProperties = properties; |
243 |
fProperties = properties; |
193 |
fRegistration = getBundleContext().registerService(classes, this, properties); |
244 |
fRegistration = getBundleContext().registerService(classes.toArray(new String[classes.size()]), this, properties); |
194 |
|
245 |
|
195 |
/* |
246 |
/* |
196 |
* Retrieve the OBJECTCLASS property directly from the service |
247 |
* Retrieve the OBJECTCLASS property directly from the service |
Lines 248-254
Link Here
|
248 |
* De-registers this service. |
299 |
* De-registers this service. |
249 |
* |
300 |
* |
250 |
*/ |
301 |
*/ |
251 |
protected void unregister() { |
302 |
private void unregister() { |
252 |
if (fRegistration != null) { |
303 |
if (fRegistration != null) { |
253 |
fRegistration.unregister(); |
304 |
fRegistration.unregister(); |
254 |
} |
305 |
} |