blob: ba238fe0454f71503449de933aa3d150b6c978c7 [file] [log] [blame]
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<title>Source code</title>
<link rel="stylesheet" type="text/css" href="../../../../../../stylesheet.css" title="Style">
</head>
<body>
<div class="sourceContainer">
<pre><span class="sourceLineNo">001</span>/*<a name="line.1"></a>
<span class="sourceLineNo">002</span> * Licensed to the Apache Software Foundation (ASF) under one<a name="line.2"></a>
<span class="sourceLineNo">003</span> * or more contributor license agreements. See the NOTICE file<a name="line.3"></a>
<span class="sourceLineNo">004</span> * distributed with this work for additional information<a name="line.4"></a>
<span class="sourceLineNo">005</span> * regarding copyright ownership. The ASF licenses this file<a name="line.5"></a>
<span class="sourceLineNo">006</span> * to you under the Apache License, Version 2.0 (the<a name="line.6"></a>
<span class="sourceLineNo">007</span> * "License"); you may not use this file except in compliance<a name="line.7"></a>
<span class="sourceLineNo">008</span> * with the License. You may obtain a copy of the License at<a name="line.8"></a>
<span class="sourceLineNo">009</span> *<a name="line.9"></a>
<span class="sourceLineNo">010</span> * http://www.apache.org/licenses/LICENSE-2.0<a name="line.10"></a>
<span class="sourceLineNo">011</span> *<a name="line.11"></a>
<span class="sourceLineNo">012</span> * Unless required by applicable law or agreed to in writing,<a name="line.12"></a>
<span class="sourceLineNo">013</span> * software distributed under the License is distributed on an<a name="line.13"></a>
<span class="sourceLineNo">014</span> * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY<a name="line.14"></a>
<span class="sourceLineNo">015</span> * KIND, either express or implied. See the License for the<a name="line.15"></a>
<span class="sourceLineNo">016</span> * specific language governing permissions and limitations<a name="line.16"></a>
<span class="sourceLineNo">017</span> * under the License.<a name="line.17"></a>
<span class="sourceLineNo">018</span> */<a name="line.18"></a>
<span class="sourceLineNo">019</span>package org.apache.felix.ipojo.util;<a name="line.19"></a>
<span class="sourceLineNo">020</span><a name="line.20"></a>
<span class="sourceLineNo">021</span>import java.util.ArrayList;<a name="line.21"></a>
<span class="sourceLineNo">022</span>import java.util.Arrays;<a name="line.22"></a>
<span class="sourceLineNo">023</span>import java.util.HashMap;<a name="line.23"></a>
<span class="sourceLineNo">024</span>import java.util.Iterator;<a name="line.24"></a>
<span class="sourceLineNo">025</span>import java.util.LinkedList;<a name="line.25"></a>
<span class="sourceLineNo">026</span>import java.util.List;<a name="line.26"></a>
<span class="sourceLineNo">027</span>import java.util.Map;<a name="line.27"></a>
<span class="sourceLineNo">028</span><a name="line.28"></a>
<span class="sourceLineNo">029</span>import org.apache.felix.ipojo.context.ServiceReferenceImpl;<a name="line.29"></a>
<span class="sourceLineNo">030</span>import org.osgi.framework.BundleContext;<a name="line.30"></a>
<span class="sourceLineNo">031</span>import org.osgi.framework.Constants;<a name="line.31"></a>
<span class="sourceLineNo">032</span>import org.osgi.framework.Filter;<a name="line.32"></a>
<span class="sourceLineNo">033</span>import org.osgi.framework.InvalidSyntaxException;<a name="line.33"></a>
<span class="sourceLineNo">034</span>import org.osgi.framework.ServiceEvent;<a name="line.34"></a>
<span class="sourceLineNo">035</span>import org.osgi.framework.ServiceListener;<a name="line.35"></a>
<span class="sourceLineNo">036</span>import org.osgi.framework.ServiceReference;<a name="line.36"></a>
<span class="sourceLineNo">037</span><a name="line.37"></a>
<span class="sourceLineNo">038</span>/**<a name="line.38"></a>
<span class="sourceLineNo">039</span> * Utility class close to the OSGi Service Tracker.<a name="line.39"></a>
<span class="sourceLineNo">040</span> * This class is used when tracking dynamic services is required.<a name="line.40"></a>
<span class="sourceLineNo">041</span> * @author &lt;a href="mailto:dev@felix.apache.org"&gt;Felix Project Team&lt;/a&gt;<a name="line.41"></a>
<span class="sourceLineNo">042</span> */<a name="line.42"></a>
<span class="sourceLineNo">043</span>public class Tracker implements TrackerCustomizer {<a name="line.43"></a>
<span class="sourceLineNo">044</span><a name="line.44"></a>
<span class="sourceLineNo">045</span> /**<a name="line.45"></a>
<span class="sourceLineNo">046</span> * The bundle context against which this Tracker object is tracking.<a name="line.46"></a>
<span class="sourceLineNo">047</span> */<a name="line.47"></a>
<span class="sourceLineNo">048</span> protected BundleContext m_context;<a name="line.48"></a>
<span class="sourceLineNo">049</span><a name="line.49"></a>
<span class="sourceLineNo">050</span> /**<a name="line.50"></a>
<span class="sourceLineNo">051</span> * the filter specifying search criteria for the services to track.<a name="line.51"></a>
<span class="sourceLineNo">052</span> */<a name="line.52"></a>
<span class="sourceLineNo">053</span> protected Filter m_filter;<a name="line.53"></a>
<span class="sourceLineNo">054</span><a name="line.54"></a>
<span class="sourceLineNo">055</span> /**<a name="line.55"></a>
<span class="sourceLineNo">056</span> * The TrackerCustomizer object for this tracker.<a name="line.56"></a>
<span class="sourceLineNo">057</span> */<a name="line.57"></a>
<span class="sourceLineNo">058</span> protected TrackerCustomizer m_customizer;<a name="line.58"></a>
<span class="sourceLineNo">059</span><a name="line.59"></a>
<span class="sourceLineNo">060</span> /**<a name="line.60"></a>
<span class="sourceLineNo">061</span> * The filter string for use when adding the ServiceListener.<a name="line.61"></a>
<span class="sourceLineNo">062</span> * If this field is set, then certain optimizations can be taken since we don't have a user supplied filter.<a name="line.62"></a>
<span class="sourceLineNo">063</span> */<a name="line.63"></a>
<span class="sourceLineNo">064</span> protected String m_listenerFilter;<a name="line.64"></a>
<span class="sourceLineNo">065</span><a name="line.65"></a>
<span class="sourceLineNo">066</span> /**<a name="line.66"></a>
<span class="sourceLineNo">067</span> * The class name to be tracked. If this field is set, then we are<a name="line.67"></a>
<span class="sourceLineNo">068</span> * tracking by class name.<a name="line.68"></a>
<span class="sourceLineNo">069</span> */<a name="line.69"></a>
<span class="sourceLineNo">070</span> private String m_trackClass;<a name="line.70"></a>
<span class="sourceLineNo">071</span><a name="line.71"></a>
<span class="sourceLineNo">072</span> /**<a name="line.72"></a>
<span class="sourceLineNo">073</span> * The reference to be tracked. If this field is set, then we are<a name="line.73"></a>
<span class="sourceLineNo">074</span> * tracking a single ServiceReference.<a name="line.74"></a>
<span class="sourceLineNo">075</span> */<a name="line.75"></a>
<span class="sourceLineNo">076</span> private ServiceReference m_trackReference;<a name="line.76"></a>
<span class="sourceLineNo">077</span><a name="line.77"></a>
<span class="sourceLineNo">078</span> /**<a name="line.78"></a>
<span class="sourceLineNo">079</span> * The tracked services: ServiceReference object -&gt; customized.<a name="line.79"></a>
<span class="sourceLineNo">080</span> *Object and ServiceListener object<a name="line.80"></a>
<span class="sourceLineNo">081</span> */<a name="line.81"></a>
<span class="sourceLineNo">082</span> private Tracked m_tracked;<a name="line.82"></a>
<span class="sourceLineNo">083</span><a name="line.83"></a>
<span class="sourceLineNo">084</span> /**<a name="line.84"></a>
<span class="sourceLineNo">085</span> * The cached ServiceReference for getServiceReference.<a name="line.85"></a>
<span class="sourceLineNo">086</span> * This field is volatile since it is accessed by multiple threads.<a name="line.86"></a>
<span class="sourceLineNo">087</span> */<a name="line.87"></a>
<span class="sourceLineNo">088</span> private volatile ServiceReference m_cachedReference;<a name="line.88"></a>
<span class="sourceLineNo">089</span><a name="line.89"></a>
<span class="sourceLineNo">090</span> /**<a name="line.90"></a>
<span class="sourceLineNo">091</span> * The cached service object for getService. This field is volatile<a name="line.91"></a>
<span class="sourceLineNo">092</span> * since it is accessed by multiple threads.<a name="line.92"></a>
<span class="sourceLineNo">093</span> */<a name="line.93"></a>
<span class="sourceLineNo">094</span> private volatile Object m_cachedService;<a name="line.94"></a>
<span class="sourceLineNo">095</span><a name="line.95"></a>
<span class="sourceLineNo">096</span> /**<a name="line.96"></a>
<span class="sourceLineNo">097</span> * Creates a Tracker object on the specified ServiceReference object.<a name="line.97"></a>
<span class="sourceLineNo">098</span> * The service referenced by the specified ServiceReference object will be tracked by this Tracker.<a name="line.98"></a>
<span class="sourceLineNo">099</span> * @param context The BundleContext object against which the tracking is done.<a name="line.99"></a>
<span class="sourceLineNo">100</span> * @param reference The ServiceReference object for the service to be tracked.<a name="line.100"></a>
<span class="sourceLineNo">101</span> * @param customizer The customizer object to call when services are added, modified, or removed in this Tracker object. If customizer is null, then this Tracker object will be used as<a name="line.101"></a>
<span class="sourceLineNo">102</span> * the TrackerCustomizer object and the Tracker object will call the TrackerCustomizer methods on itself.<a name="line.102"></a>
<span class="sourceLineNo">103</span> */<a name="line.103"></a>
<span class="sourceLineNo">104</span> public Tracker(BundleContext context, ServiceReference reference, TrackerCustomizer customizer) {<a name="line.104"></a>
<span class="sourceLineNo">105</span> m_context = context;<a name="line.105"></a>
<span class="sourceLineNo">106</span> m_trackReference = reference;<a name="line.106"></a>
<span class="sourceLineNo">107</span> m_trackClass = null;<a name="line.107"></a>
<span class="sourceLineNo">108</span> if (customizer == null) {<a name="line.108"></a>
<span class="sourceLineNo">109</span> m_customizer = this;<a name="line.109"></a>
<span class="sourceLineNo">110</span> } else {<a name="line.110"></a>
<span class="sourceLineNo">111</span> m_customizer = customizer;<a name="line.111"></a>
<span class="sourceLineNo">112</span> }<a name="line.112"></a>
<span class="sourceLineNo">113</span> m_listenerFilter = "(" + Constants.SERVICE_ID + "=" + reference.getProperty(Constants.SERVICE_ID).toString() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$<a name="line.113"></a>
<span class="sourceLineNo">114</span> try {<a name="line.114"></a>
<span class="sourceLineNo">115</span> this.m_filter = context.createFilter(m_listenerFilter);<a name="line.115"></a>
<span class="sourceLineNo">116</span> } catch (InvalidSyntaxException e) { // we could only get this exception if the ServiceReference was invalid<a name="line.116"></a>
<span class="sourceLineNo">117</span> throw new IllegalArgumentException("unexpected InvalidSyntaxException", e); //$NON-NLS-1$<a name="line.117"></a>
<span class="sourceLineNo">118</span> }<a name="line.118"></a>
<span class="sourceLineNo">119</span> }<a name="line.119"></a>
<span class="sourceLineNo">120</span><a name="line.120"></a>
<span class="sourceLineNo">121</span> /**<a name="line.121"></a>
<span class="sourceLineNo">122</span> * Creates a Tracker object on the specified class name.<a name="line.122"></a>
<span class="sourceLineNo">123</span> * Services registered under the specified class name will be tracked by this Tracker object.<a name="line.123"></a>
<span class="sourceLineNo">124</span> * @param context the BundleContext object against which the tracking is done.<a name="line.124"></a>
<span class="sourceLineNo">125</span> * @param clazz the Class name of the services to be tracked.<a name="line.125"></a>
<span class="sourceLineNo">126</span> * @param customizer the customizer object to call when services are added, modified, or removed in this Tracker object. If customizer is null, then this Tracker object will be used as<a name="line.126"></a>
<span class="sourceLineNo">127</span> * the TrackerCustomizer object and the Tracker object will call the TrackerCustomizer methods on itself.<a name="line.127"></a>
<span class="sourceLineNo">128</span> */<a name="line.128"></a>
<span class="sourceLineNo">129</span> public Tracker(BundleContext context, String clazz, TrackerCustomizer customizer) {<a name="line.129"></a>
<span class="sourceLineNo">130</span> // Security Check<a name="line.130"></a>
<span class="sourceLineNo">131</span> if (! SecurityHelper.hasPermissionToGetService(clazz, context)) {<a name="line.131"></a>
<span class="sourceLineNo">132</span> throw new SecurityException("The bundle " + context.getBundle().getBundleId()<a name="line.132"></a>
<span class="sourceLineNo">133</span> + " does not have the permission to get the service " + clazz);<a name="line.133"></a>
<span class="sourceLineNo">134</span> }<a name="line.134"></a>
<span class="sourceLineNo">135</span><a name="line.135"></a>
<span class="sourceLineNo">136</span> this.m_context = context;<a name="line.136"></a>
<span class="sourceLineNo">137</span> this.m_trackReference = null;<a name="line.137"></a>
<span class="sourceLineNo">138</span> this.m_trackClass = clazz;<a name="line.138"></a>
<span class="sourceLineNo">139</span> if (customizer == null) {<a name="line.139"></a>
<span class="sourceLineNo">140</span> m_customizer = this;<a name="line.140"></a>
<span class="sourceLineNo">141</span> } else {<a name="line.141"></a>
<span class="sourceLineNo">142</span> m_customizer = customizer;<a name="line.142"></a>
<span class="sourceLineNo">143</span> }<a name="line.143"></a>
<span class="sourceLineNo">144</span> this.m_listenerFilter = "(" + Constants.OBJECTCLASS + "=" + clazz + ")";<a name="line.144"></a>
<span class="sourceLineNo">145</span> try {<a name="line.145"></a>
<span class="sourceLineNo">146</span> this.m_filter = context.createFilter(m_listenerFilter);<a name="line.146"></a>
<span class="sourceLineNo">147</span> } catch (InvalidSyntaxException e) { // we could only get this exception<a name="line.147"></a>
<span class="sourceLineNo">148</span> // if the clazz argument was<a name="line.148"></a>
<span class="sourceLineNo">149</span> // malformed<a name="line.149"></a>
<span class="sourceLineNo">150</span> throw new IllegalArgumentException("unexpected InvalidSyntaxException", e);<a name="line.150"></a>
<span class="sourceLineNo">151</span> }<a name="line.151"></a>
<span class="sourceLineNo">152</span> }<a name="line.152"></a>
<span class="sourceLineNo">153</span><a name="line.153"></a>
<span class="sourceLineNo">154</span> /**<a name="line.154"></a>
<span class="sourceLineNo">155</span> * Creates a Tracker object on the specified Filter object.<a name="line.155"></a>
<span class="sourceLineNo">156</span> * &lt;p&gt;<a name="line.156"></a>
<span class="sourceLineNo">157</span> * Services which match the specified Filter object will be tracked by this Tracker object.<a name="line.157"></a>
<span class="sourceLineNo">158</span> * @param context the BundleContext object against which the tracking is done.<a name="line.158"></a>
<span class="sourceLineNo">159</span> * @param filter the Filter object to select the services to be tracked.<a name="line.159"></a>
<span class="sourceLineNo">160</span> * @param customizer The customizer object to call when services are added, modified, or removed in this Tracker object. If customizer is null, then this Tracker object will be used as the<a name="line.160"></a>
<span class="sourceLineNo">161</span> * TrackerCustomizer object and the Tracker object will call the TrackerCustomizer methods on itself.<a name="line.161"></a>
<span class="sourceLineNo">162</span> */<a name="line.162"></a>
<span class="sourceLineNo">163</span> public Tracker(BundleContext context, Filter filter, TrackerCustomizer customizer) {<a name="line.163"></a>
<span class="sourceLineNo">164</span> this.m_context = context;<a name="line.164"></a>
<span class="sourceLineNo">165</span> this.m_trackReference = null;<a name="line.165"></a>
<span class="sourceLineNo">166</span> this.m_trackClass = null;<a name="line.166"></a>
<span class="sourceLineNo">167</span> this.m_listenerFilter = null;<a name="line.167"></a>
<span class="sourceLineNo">168</span> this.m_filter = filter;<a name="line.168"></a>
<span class="sourceLineNo">169</span> if (customizer == null) {<a name="line.169"></a>
<span class="sourceLineNo">170</span> m_customizer = this;<a name="line.170"></a>
<span class="sourceLineNo">171</span> } else {<a name="line.171"></a>
<span class="sourceLineNo">172</span> m_customizer = customizer;<a name="line.172"></a>
<span class="sourceLineNo">173</span> }<a name="line.173"></a>
<span class="sourceLineNo">174</span> if ((context == null) || (filter == null)) { // we throw a NPE here to be consistent with the other constructors<a name="line.174"></a>
<span class="sourceLineNo">175</span> throw new NullPointerException(); // NOPMD by clement on 29/02/08 14:12<a name="line.175"></a>
<span class="sourceLineNo">176</span> }<a name="line.176"></a>
<span class="sourceLineNo">177</span> }<a name="line.177"></a>
<span class="sourceLineNo">178</span><a name="line.178"></a>
<span class="sourceLineNo">179</span> /**<a name="line.179"></a>
<span class="sourceLineNo">180</span> * Opens this Tracker object and begin tracking services.<a name="line.180"></a>
<span class="sourceLineNo">181</span> * &lt;p&gt;<a name="line.181"></a>
<span class="sourceLineNo">182</span> * Services which match the search criteria specified when this Tracker object was created are now tracked by this Tracker object.<a name="line.182"></a>
<span class="sourceLineNo">183</span> */<a name="line.183"></a>
<span class="sourceLineNo">184</span> public synchronized void open() {<a name="line.184"></a>
<span class="sourceLineNo">185</span> if (m_tracked != null) { return; }<a name="line.185"></a>
<span class="sourceLineNo">186</span><a name="line.186"></a>
<span class="sourceLineNo">187</span> m_tracked = new Tracked();<a name="line.187"></a>
<span class="sourceLineNo">188</span> synchronized (m_tracked) {<a name="line.188"></a>
<span class="sourceLineNo">189</span> try {<a name="line.189"></a>
<span class="sourceLineNo">190</span> m_context.addServiceListener(m_tracked, m_listenerFilter);<a name="line.190"></a>
<span class="sourceLineNo">191</span> ServiceReference[] references;<a name="line.191"></a>
<span class="sourceLineNo">192</span> if (m_listenerFilter == null) { // user supplied filter<a name="line.192"></a>
<span class="sourceLineNo">193</span> references = getInitialReferences(null, m_filter.toString());<a name="line.193"></a>
<span class="sourceLineNo">194</span> } else { // constructor supplied filter<a name="line.194"></a>
<span class="sourceLineNo">195</span> if (m_trackClass == null) {<a name="line.195"></a>
<span class="sourceLineNo">196</span> references = new ServiceReference[] { m_trackReference };<a name="line.196"></a>
<span class="sourceLineNo">197</span> } else {<a name="line.197"></a>
<span class="sourceLineNo">198</span> references = getInitialReferences(m_trackClass, null);<a name="line.198"></a>
<span class="sourceLineNo">199</span> }<a name="line.199"></a>
<span class="sourceLineNo">200</span> }<a name="line.200"></a>
<span class="sourceLineNo">201</span><a name="line.201"></a>
<span class="sourceLineNo">202</span> m_tracked.setInitialServices(references); // set tracked with<a name="line.202"></a>
<span class="sourceLineNo">203</span> // the initial<a name="line.203"></a>
<span class="sourceLineNo">204</span> // references<a name="line.204"></a>
<span class="sourceLineNo">205</span> } catch (InvalidSyntaxException e) {<a name="line.205"></a>
<span class="sourceLineNo">206</span> throw new IllegalStateException("unexpected InvalidSyntaxException", e); //$NON-NLS-1$<a name="line.206"></a>
<span class="sourceLineNo">207</span> }<a name="line.207"></a>
<span class="sourceLineNo">208</span> }<a name="line.208"></a>
<span class="sourceLineNo">209</span> /* Call tracked outside of synchronized region */<a name="line.209"></a>
<span class="sourceLineNo">210</span> m_tracked.trackInitialServices(); // process the initial references<a name="line.210"></a>
<span class="sourceLineNo">211</span> }<a name="line.211"></a>
<span class="sourceLineNo">212</span><a name="line.212"></a>
<span class="sourceLineNo">213</span> /**<a name="line.213"></a>
<span class="sourceLineNo">214</span> * Returns the list of initial ServiceReference objects that will be tracked by this Tracker object.<a name="line.214"></a>
<span class="sourceLineNo">215</span> * @param trackClass the class name with which the service was registered, or null for all services.<a name="line.215"></a>
<span class="sourceLineNo">216</span> * @param filterString the filter criteria or null for all services.<a name="line.216"></a>
<span class="sourceLineNo">217</span> * @return the list of initial ServiceReference objects.<a name="line.217"></a>
<span class="sourceLineNo">218</span> * @throws InvalidSyntaxException if the filter uses an invalid syntax.<a name="line.218"></a>
<span class="sourceLineNo">219</span> */<a name="line.219"></a>
<span class="sourceLineNo">220</span> private ServiceReference[] getInitialReferences(String trackClass, String filterString) throws InvalidSyntaxException {<a name="line.220"></a>
<span class="sourceLineNo">221</span> return m_context.getServiceReferences(trackClass, filterString);<a name="line.221"></a>
<span class="sourceLineNo">222</span> }<a name="line.222"></a>
<span class="sourceLineNo">223</span><a name="line.223"></a>
<span class="sourceLineNo">224</span> /**<a name="line.224"></a>
<span class="sourceLineNo">225</span> * Closes this Tracker object.<a name="line.225"></a>
<span class="sourceLineNo">226</span> * &lt;p&gt;<a name="line.226"></a>
<span class="sourceLineNo">227</span> * This method should be called when this Tracker object should end the tracking of services.<a name="line.227"></a>
<span class="sourceLineNo">228</span> */<a name="line.228"></a>
<span class="sourceLineNo">229</span> public synchronized void close() {<a name="line.229"></a>
<span class="sourceLineNo">230</span> if (m_tracked == null) { return; }<a name="line.230"></a>
<span class="sourceLineNo">231</span><a name="line.231"></a>
<span class="sourceLineNo">232</span> m_tracked.close();<a name="line.232"></a>
<span class="sourceLineNo">233</span> ServiceReference[] references = getServiceReferences();<a name="line.233"></a>
<span class="sourceLineNo">234</span> Tracked outgoing = m_tracked;<a name="line.234"></a>
<span class="sourceLineNo">235</span><a name="line.235"></a>
<span class="sourceLineNo">236</span> try {<a name="line.236"></a>
<span class="sourceLineNo">237</span> m_context.removeServiceListener(outgoing);<a name="line.237"></a>
<span class="sourceLineNo">238</span> } catch (IllegalStateException e) { //NOPMD<a name="line.238"></a>
<span class="sourceLineNo">239</span> /* In case the context was stopped. */<a name="line.239"></a>
<span class="sourceLineNo">240</span> }<a name="line.240"></a>
<span class="sourceLineNo">241</span> if (references != null) {<a name="line.241"></a>
<span class="sourceLineNo">242</span> for (ServiceReference reference : references) {<a name="line.242"></a>
<span class="sourceLineNo">243</span> outgoing.untrack(reference);<a name="line.243"></a>
<span class="sourceLineNo">244</span> }<a name="line.244"></a>
<span class="sourceLineNo">245</span> }<a name="line.245"></a>
<span class="sourceLineNo">246</span> m_tracked = null;<a name="line.246"></a>
<span class="sourceLineNo">247</span><a name="line.247"></a>
<span class="sourceLineNo">248</span> }<a name="line.248"></a>
<span class="sourceLineNo">249</span><a name="line.249"></a>
<span class="sourceLineNo">250</span> /**<a name="line.250"></a>
<span class="sourceLineNo">251</span> * Default implementation of the TrackerCustomizer.addingService method.<a name="line.251"></a>
<span class="sourceLineNo">252</span> * &lt;p&gt;<a name="line.252"></a>
<span class="sourceLineNo">253</span> * This method is only called when this Tracker object has been constructed with a null TrackerCustomizer argument. The default implementation returns the result of calling getService,<a name="line.253"></a>
<span class="sourceLineNo">254</span> * on the BundleContext object with which this Tracker object was created, passing the specified ServiceReference object.<a name="line.254"></a>
<span class="sourceLineNo">255</span> * &lt;p&gt;<a name="line.255"></a>
<span class="sourceLineNo">256</span> * This method can be overridden in a subclass to customize the service object to be tracked for the service being added. In that case, take care not to rely on the default implementation of removedService that will unget the service.<a name="line.256"></a>
<span class="sourceLineNo">257</span> * @param reference the Reference to service being added to this Tracker object.<a name="line.257"></a>
<span class="sourceLineNo">258</span> * @return The service object to be tracked for the service added to this Tracker object.<a name="line.258"></a>
<span class="sourceLineNo">259</span> * @see TrackerCustomizer<a name="line.259"></a>
<span class="sourceLineNo">260</span> */<a name="line.260"></a>
<span class="sourceLineNo">261</span> public boolean addingService(ServiceReference reference) {<a name="line.261"></a>
<span class="sourceLineNo">262</span> return true;<a name="line.262"></a>
<span class="sourceLineNo">263</span> }<a name="line.263"></a>
<span class="sourceLineNo">264</span><a name="line.264"></a>
<span class="sourceLineNo">265</span> /**<a name="line.265"></a>
<span class="sourceLineNo">266</span> * Default implementation of the TrackerCustomizer.addedService method.<a name="line.266"></a>
<span class="sourceLineNo">267</span> * @param reference the added reference.<a name="line.267"></a>
<span class="sourceLineNo">268</span> * @see org.apache.felix.ipojo.util.TrackerCustomizer#addedService(org.osgi.framework.ServiceReference)<a name="line.268"></a>
<span class="sourceLineNo">269</span> */<a name="line.269"></a>
<span class="sourceLineNo">270</span> public void addedService(ServiceReference reference) {<a name="line.270"></a>
<span class="sourceLineNo">271</span> // Nothing to do.<a name="line.271"></a>
<span class="sourceLineNo">272</span> }<a name="line.272"></a>
<span class="sourceLineNo">273</span><a name="line.273"></a>
<span class="sourceLineNo">274</span> /**<a name="line.274"></a>
<span class="sourceLineNo">275</span> * Default implementation of the TrackerCustomizer.modifiedService method.<a name="line.275"></a>
<span class="sourceLineNo">276</span> * &lt;p&gt;<a name="line.276"></a>
<span class="sourceLineNo">277</span> * This method is only called when this Tracker object has been constructed with a null TrackerCustomizer argument. The default implementation does nothing.<a name="line.277"></a>
<span class="sourceLineNo">278</span> * @param reference the Reference to modified service.<a name="line.278"></a>
<span class="sourceLineNo">279</span> * @param service The service object for the modified service.<a name="line.279"></a>
<span class="sourceLineNo">280</span> * @see TrackerCustomizer<a name="line.280"></a>
<span class="sourceLineNo">281</span> */<a name="line.281"></a>
<span class="sourceLineNo">282</span> public void modifiedService(ServiceReference reference, Object service) {<a name="line.282"></a>
<span class="sourceLineNo">283</span> // Nothing to do.<a name="line.283"></a>
<span class="sourceLineNo">284</span> }<a name="line.284"></a>
<span class="sourceLineNo">285</span><a name="line.285"></a>
<span class="sourceLineNo">286</span> /**<a name="line.286"></a>
<span class="sourceLineNo">287</span> * Default implementation of the TrackerCustomizer.removedService method.<a name="line.287"></a>
<span class="sourceLineNo">288</span> * &lt;p&gt;<a name="line.288"></a>
<span class="sourceLineNo">289</span> * This method is only called when this Tracker object has been constructed with a null TrackerCustomizer argument. The default implementation calls ungetService, on the<a name="line.289"></a>
<span class="sourceLineNo">290</span> * BundleContext object with which this Tracker object was created, passing the specified ServiceReference object.<a name="line.290"></a>
<span class="sourceLineNo">291</span> * &lt;p&gt;<a name="line.291"></a>
<span class="sourceLineNo">292</span> * This method can be overridden in a subclass. If the default implementation of addingService method was used, this method must unget the service.<a name="line.292"></a>
<span class="sourceLineNo">293</span> * @param reference the Reference to removed service.<a name="line.293"></a>
<span class="sourceLineNo">294</span> * @param service The service object for the removed service.<a name="line.294"></a>
<span class="sourceLineNo">295</span> * @see TrackerCustomizer<a name="line.295"></a>
<span class="sourceLineNo">296</span> */<a name="line.296"></a>
<span class="sourceLineNo">297</span> public void removedService(ServiceReference reference, Object service) {<a name="line.297"></a>
<span class="sourceLineNo">298</span> m_context.ungetService(reference);<a name="line.298"></a>
<span class="sourceLineNo">299</span> }<a name="line.299"></a>
<span class="sourceLineNo">300</span><a name="line.300"></a>
<span class="sourceLineNo">301</span> /**<a name="line.301"></a>
<span class="sourceLineNo">302</span> * Waits for at least one service to be tracked by this Tracker object.<a name="line.302"></a>
<span class="sourceLineNo">303</span> * &lt;p&gt;<a name="line.303"></a>
<span class="sourceLineNo">304</span> * It is strongly recommended that waitForService is not used during the calling of the BundleActivator methods. BundleActivator methods are expected to complete in a short period of time.<a name="line.304"></a>
<span class="sourceLineNo">305</span> * @param timeout the time interval in milliseconds to wait. If zero, the method will wait indefinately.<a name="line.305"></a>
<span class="sourceLineNo">306</span> * @return Returns the result of getService().<a name="line.306"></a>
<span class="sourceLineNo">307</span> * @throws InterruptedException If another thread has interrupted the current thread.<a name="line.307"></a>
<span class="sourceLineNo">308</span> */<a name="line.308"></a>
<span class="sourceLineNo">309</span> public Object waitForService(long timeout) throws InterruptedException {<a name="line.309"></a>
<span class="sourceLineNo">310</span> if (timeout &lt; 0) { throw new IllegalArgumentException("timeout value is negative"); }<a name="line.310"></a>
<span class="sourceLineNo">311</span> Object object = getService();<a name="line.311"></a>
<span class="sourceLineNo">312</span> while (object == null) {<a name="line.312"></a>
<span class="sourceLineNo">313</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.313"></a>
<span class="sourceLineNo">314</span> if (tracked == null) { /* if Tracker is not open */<a name="line.314"></a>
<span class="sourceLineNo">315</span> return null;<a name="line.315"></a>
<span class="sourceLineNo">316</span> }<a name="line.316"></a>
<span class="sourceLineNo">317</span> synchronized (tracked) {<a name="line.317"></a>
<span class="sourceLineNo">318</span> if (tracked.size() == 0) {<a name="line.318"></a>
<span class="sourceLineNo">319</span> tracked.wait(timeout);<a name="line.319"></a>
<span class="sourceLineNo">320</span> }<a name="line.320"></a>
<span class="sourceLineNo">321</span> }<a name="line.321"></a>
<span class="sourceLineNo">322</span> object = getService();<a name="line.322"></a>
<span class="sourceLineNo">323</span> if (timeout &gt; 0) { return object; }<a name="line.323"></a>
<span class="sourceLineNo">324</span> }<a name="line.324"></a>
<span class="sourceLineNo">325</span> return object;<a name="line.325"></a>
<span class="sourceLineNo">326</span> }<a name="line.326"></a>
<span class="sourceLineNo">327</span><a name="line.327"></a>
<span class="sourceLineNo">328</span> /**<a name="line.328"></a>
<span class="sourceLineNo">329</span> * Returns an array of ServiceReference objects for all services being tracked by this Tracker object.<a name="line.329"></a>
<span class="sourceLineNo">330</span> * @return Array of ServiceReference objects or &lt;code&gt;null&lt;/code&gt; if no service are being tracked.<a name="line.330"></a>
<span class="sourceLineNo">331</span> */<a name="line.331"></a>
<span class="sourceLineNo">332</span> public ServiceReference[] getServiceReferences() {<a name="line.332"></a>
<span class="sourceLineNo">333</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.333"></a>
<span class="sourceLineNo">334</span> if (tracked == null) { // if Tracker is not open<a name="line.334"></a>
<span class="sourceLineNo">335</span> return null;<a name="line.335"></a>
<span class="sourceLineNo">336</span> }<a name="line.336"></a>
<span class="sourceLineNo">337</span> synchronized (tracked) {<a name="line.337"></a>
<span class="sourceLineNo">338</span> int length = tracked.size();<a name="line.338"></a>
<span class="sourceLineNo">339</span> if (length == 0) { return null; }<a name="line.339"></a>
<span class="sourceLineNo">340</span> ServiceReference[] references = new ServiceReference[length];<a name="line.340"></a>
<span class="sourceLineNo">341</span> Iterator keys = tracked.keySet().iterator();<a name="line.341"></a>
<span class="sourceLineNo">342</span> for (int i = 0; i &lt; length; i++) {<a name="line.342"></a>
<span class="sourceLineNo">343</span> references[i] = (ServiceReference) keys.next();<a name="line.343"></a>
<span class="sourceLineNo">344</span> }<a name="line.344"></a>
<span class="sourceLineNo">345</span> return references;<a name="line.345"></a>
<span class="sourceLineNo">346</span> }<a name="line.346"></a>
<span class="sourceLineNo">347</span> }<a name="line.347"></a>
<span class="sourceLineNo">348</span><a name="line.348"></a>
<span class="sourceLineNo">349</span> /**<a name="line.349"></a>
<span class="sourceLineNo">350</span> * Gets the list of stored service references.<a name="line.350"></a>
<span class="sourceLineNo">351</span> * @return the list containing service references<a name="line.351"></a>
<span class="sourceLineNo">352</span> */<a name="line.352"></a>
<span class="sourceLineNo">353</span> public List&lt;ServiceReference&gt; getServiceReferencesList() {<a name="line.353"></a>
<span class="sourceLineNo">354</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.354"></a>
<span class="sourceLineNo">355</span> if (tracked == null) { // if Tracker is not open<a name="line.355"></a>
<span class="sourceLineNo">356</span> return null;<a name="line.356"></a>
<span class="sourceLineNo">357</span> }<a name="line.357"></a>
<span class="sourceLineNo">358</span> synchronized (tracked) {<a name="line.358"></a>
<span class="sourceLineNo">359</span> int length = tracked.size();<a name="line.359"></a>
<span class="sourceLineNo">360</span> if (length == 0) { return null; }<a name="line.360"></a>
<span class="sourceLineNo">361</span> List&lt;ServiceReference&gt; references = new ArrayList&lt;ServiceReference&gt;(length);<a name="line.361"></a>
<span class="sourceLineNo">362</span> references.addAll(tracked.keySet());<a name="line.362"></a>
<span class="sourceLineNo">363</span> // The resulting array is sorted by ranking.<a name="line.363"></a>
<span class="sourceLineNo">364</span> return references;<a name="line.364"></a>
<span class="sourceLineNo">365</span> }<a name="line.365"></a>
<span class="sourceLineNo">366</span> }<a name="line.366"></a>
<span class="sourceLineNo">367</span><a name="line.367"></a>
<span class="sourceLineNo">368</span> /**<a name="line.368"></a>
<span class="sourceLineNo">369</span> * Returns the list of references used by the tracker.<a name="line.369"></a>
<span class="sourceLineNo">370</span> * A reference becomes used when the dependency has already<a name="line.370"></a>
<span class="sourceLineNo">371</span> * called getService on this reference.<a name="line.371"></a>
<span class="sourceLineNo">372</span> * @return the list of used references.<a name="line.372"></a>
<span class="sourceLineNo">373</span> */<a name="line.373"></a>
<span class="sourceLineNo">374</span> public List&lt;ServiceReference&gt; getUsedServiceReferences() {<a name="line.374"></a>
<span class="sourceLineNo">375</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.375"></a>
<span class="sourceLineNo">376</span> if (tracked == null || tracked.size() == 0) { // if Tracker is not open or empty<a name="line.376"></a>
<span class="sourceLineNo">377</span> return null;<a name="line.377"></a>
<span class="sourceLineNo">378</span> }<a name="line.378"></a>
<span class="sourceLineNo">379</span> synchronized (tracked) {<a name="line.379"></a>
<span class="sourceLineNo">380</span> List&lt;ServiceReference&gt; references = new ArrayList&lt;ServiceReference&gt;();<a name="line.380"></a>
<span class="sourceLineNo">381</span> for (Map.Entry&lt;ServiceReference, Object&gt; entry : tracked.entrySet()) {<a name="line.381"></a>
<span class="sourceLineNo">382</span> if (entry.getValue() != null) {<a name="line.382"></a>
<span class="sourceLineNo">383</span> references.add(entry.getKey());<a name="line.383"></a>
<span class="sourceLineNo">384</span> }<a name="line.384"></a>
<span class="sourceLineNo">385</span> }<a name="line.385"></a>
<span class="sourceLineNo">386</span> return references;<a name="line.386"></a>
<span class="sourceLineNo">387</span> }<a name="line.387"></a>
<span class="sourceLineNo">388</span> }<a name="line.388"></a>
<span class="sourceLineNo">389</span><a name="line.389"></a>
<span class="sourceLineNo">390</span> /**<a name="line.390"></a>
<span class="sourceLineNo">391</span> * Returns a ServiceReference object for one of the services being tracked by this Tracker object.<a name="line.391"></a>
<span class="sourceLineNo">392</span> * If multiple services are being tracked, the service with the highest ranking (as specified in its service.ranking property) is returned.<a name="line.392"></a>
<span class="sourceLineNo">393</span> * If there is a tie in ranking, the service with the lowest service ID (as specified in its service.id property); that is, the service that was registered first is returned.<a name="line.393"></a>
<span class="sourceLineNo">394</span> * This is the same algorithm used by BundleContext.getServiceReference.<a name="line.394"></a>
<span class="sourceLineNo">395</span> * @return ServiceReference object or null if no service is being tracked.<a name="line.395"></a>
<span class="sourceLineNo">396</span> * @since 1.1<a name="line.396"></a>
<span class="sourceLineNo">397</span> */<a name="line.397"></a>
<span class="sourceLineNo">398</span> public ServiceReference getServiceReference() {<a name="line.398"></a>
<span class="sourceLineNo">399</span> ServiceReference reference = m_cachedReference;<a name="line.399"></a>
<span class="sourceLineNo">400</span> if (reference != null) { return reference; }<a name="line.400"></a>
<span class="sourceLineNo">401</span><a name="line.401"></a>
<span class="sourceLineNo">402</span> ServiceReference[] references = getServiceReferences();<a name="line.402"></a>
<span class="sourceLineNo">403</span> if (references == null) {<a name="line.403"></a>
<span class="sourceLineNo">404</span> return null;<a name="line.404"></a>
<span class="sourceLineNo">405</span> } else {<a name="line.405"></a>
<span class="sourceLineNo">406</span> // As the map is sorted, return the first element.<a name="line.406"></a>
<span class="sourceLineNo">407</span> return m_cachedReference = references[0];<a name="line.407"></a>
<span class="sourceLineNo">408</span> }<a name="line.408"></a>
<span class="sourceLineNo">409</span> }<a name="line.409"></a>
<span class="sourceLineNo">410</span><a name="line.410"></a>
<span class="sourceLineNo">411</span> /**<a name="line.411"></a>
<span class="sourceLineNo">412</span> * Returns the service object for the specified ServiceReference object if the referenced service is being tracked by this Tracker object.<a name="line.412"></a>
<span class="sourceLineNo">413</span> * @param reference the Reference to the desired service.<a name="line.413"></a>
<span class="sourceLineNo">414</span> * @return the Service object. Try to get the service if not yet tracked.<a name="line.414"></a>
<span class="sourceLineNo">415</span> */<a name="line.415"></a>
<span class="sourceLineNo">416</span> public Object getService(ServiceReference reference) {<a name="line.416"></a>
<span class="sourceLineNo">417</span> // Security Check<a name="line.417"></a>
<span class="sourceLineNo">418</span> if (! SecurityHelper.hasPermissionToGetServices((String[]) reference.getProperty(Constants.OBJECTCLASS),<a name="line.418"></a>
<span class="sourceLineNo">419</span> m_context)) {<a name="line.419"></a>
<span class="sourceLineNo">420</span> throw new SecurityException("The bundle " + m_context.getBundle().getBundleId() + " does not have"<a name="line.420"></a>
<span class="sourceLineNo">421</span> + " the permission to get the services "<a name="line.421"></a>
<span class="sourceLineNo">422</span> + Arrays.asList((String[]) reference.getProperty(Constants.OBJECTCLASS)));<a name="line.422"></a>
<span class="sourceLineNo">423</span> }<a name="line.423"></a>
<span class="sourceLineNo">424</span><a name="line.424"></a>
<span class="sourceLineNo">425</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.425"></a>
<span class="sourceLineNo">426</span> if (tracked == null) { /* if Tracker is not open */<a name="line.426"></a>
<span class="sourceLineNo">427</span> return null;<a name="line.427"></a>
<span class="sourceLineNo">428</span> }<a name="line.428"></a>
<span class="sourceLineNo">429</span> synchronized (tracked) {<a name="line.429"></a>
<span class="sourceLineNo">430</span> Object object = tracked.get(reference);<a name="line.430"></a>
<span class="sourceLineNo">431</span> if (object == null) {<a name="line.431"></a>
<span class="sourceLineNo">432</span> if (tracked.containsKey(reference)) { // Not already get but already tracked.<a name="line.432"></a>
<span class="sourceLineNo">433</span> object = m_context.getService(reference);<a name="line.433"></a>
<span class="sourceLineNo">434</span> tracked.put(reference, object);<a name="line.434"></a>
<span class="sourceLineNo">435</span> return object;<a name="line.435"></a>
<span class="sourceLineNo">436</span> }<a name="line.436"></a>
<span class="sourceLineNo">437</span> } else { // The object was already retrieved.<a name="line.437"></a>
<span class="sourceLineNo">438</span> return object;<a name="line.438"></a>
<span class="sourceLineNo">439</span> }<a name="line.439"></a>
<span class="sourceLineNo">440</span><a name="line.440"></a>
<span class="sourceLineNo">441</span> return m_context.getService(reference);<a name="line.441"></a>
<span class="sourceLineNo">442</span> }<a name="line.442"></a>
<span class="sourceLineNo">443</span> }<a name="line.443"></a>
<span class="sourceLineNo">444</span><a name="line.444"></a>
<span class="sourceLineNo">445</span> /**<a name="line.445"></a>
<span class="sourceLineNo">446</span> * Ungets the given service reference.<a name="line.446"></a>
<span class="sourceLineNo">447</span> * @param reference the service reference to unget.<a name="line.447"></a>
<span class="sourceLineNo">448</span> */<a name="line.448"></a>
<span class="sourceLineNo">449</span> public void ungetService(ServiceReference reference) {<a name="line.449"></a>
<span class="sourceLineNo">450</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.450"></a>
<span class="sourceLineNo">451</span> if (tracked == null) { /* if Tracker is not open */<a name="line.451"></a>
<span class="sourceLineNo">452</span> return;<a name="line.452"></a>
<span class="sourceLineNo">453</span> }<a name="line.453"></a>
<span class="sourceLineNo">454</span> Object object = null;<a name="line.454"></a>
<span class="sourceLineNo">455</span> synchronized (tracked) {<a name="line.455"></a>
<span class="sourceLineNo">456</span> object = tracked.get(reference);<a name="line.456"></a>
<span class="sourceLineNo">457</span> }<a name="line.457"></a>
<span class="sourceLineNo">458</span> if (object != null) {<a name="line.458"></a>
<span class="sourceLineNo">459</span> m_context.ungetService(reference);<a name="line.459"></a>
<span class="sourceLineNo">460</span> }<a name="line.460"></a>
<span class="sourceLineNo">461</span> }<a name="line.461"></a>
<span class="sourceLineNo">462</span><a name="line.462"></a>
<span class="sourceLineNo">463</span> /**<a name="line.463"></a>
<span class="sourceLineNo">464</span> * Returns an array of service objects for all services being tracked by this Tracker object.<a name="line.464"></a>
<span class="sourceLineNo">465</span> * @return Array of service objects or &lt;code&gt;null&lt;/code&gt; if no service are being tracked.<a name="line.465"></a>
<span class="sourceLineNo">466</span> */<a name="line.466"></a>
<span class="sourceLineNo">467</span> public Object[] getServices() {<a name="line.467"></a>
<span class="sourceLineNo">468</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.468"></a>
<span class="sourceLineNo">469</span> if (tracked == null) { /* if Tracker is not open */<a name="line.469"></a>
<span class="sourceLineNo">470</span> return null;<a name="line.470"></a>
<span class="sourceLineNo">471</span> }<a name="line.471"></a>
<span class="sourceLineNo">472</span> synchronized (tracked) {<a name="line.472"></a>
<span class="sourceLineNo">473</span> ServiceReference[] references = getServiceReferences();<a name="line.473"></a>
<span class="sourceLineNo">474</span> int length;<a name="line.474"></a>
<span class="sourceLineNo">475</span> if (references == null) {<a name="line.475"></a>
<span class="sourceLineNo">476</span> return null;<a name="line.476"></a>
<span class="sourceLineNo">477</span> } else {<a name="line.477"></a>
<span class="sourceLineNo">478</span> length = references.length;<a name="line.478"></a>
<span class="sourceLineNo">479</span> }<a name="line.479"></a>
<span class="sourceLineNo">480</span> Object[] objects = new Object[length];<a name="line.480"></a>
<span class="sourceLineNo">481</span> for (int i = 0; i &lt; length; i++) {<a name="line.481"></a>
<span class="sourceLineNo">482</span> objects[i] = getService(references[i]);<a name="line.482"></a>
<span class="sourceLineNo">483</span> }<a name="line.483"></a>
<span class="sourceLineNo">484</span> return objects;<a name="line.484"></a>
<span class="sourceLineNo">485</span> }<a name="line.485"></a>
<span class="sourceLineNo">486</span> }<a name="line.486"></a>
<span class="sourceLineNo">487</span><a name="line.487"></a>
<span class="sourceLineNo">488</span> /**<a name="line.488"></a>
<span class="sourceLineNo">489</span> * Returns a service object for one of the services being tracked by this Tracker object.<a name="line.489"></a>
<span class="sourceLineNo">490</span> * &lt;p&gt;<a name="line.490"></a>
<span class="sourceLineNo">491</span> * If any services are being tracked, this method returns the result of calling getService(getServiceReference()).<a name="line.491"></a>
<span class="sourceLineNo">492</span> * @return Service object or &lt;code&gt;null&lt;/code&gt; if no service is being tracked.<a name="line.492"></a>
<span class="sourceLineNo">493</span> */<a name="line.493"></a>
<span class="sourceLineNo">494</span> public Object getService() {<a name="line.494"></a>
<span class="sourceLineNo">495</span> Object service = m_cachedService;<a name="line.495"></a>
<span class="sourceLineNo">496</span> if (service != null) { return service; }<a name="line.496"></a>
<span class="sourceLineNo">497</span> ServiceReference reference = getServiceReference();<a name="line.497"></a>
<span class="sourceLineNo">498</span> if (reference == null) { return null; }<a name="line.498"></a>
<span class="sourceLineNo">499</span> return m_cachedService = getService(reference);<a name="line.499"></a>
<span class="sourceLineNo">500</span> }<a name="line.500"></a>
<span class="sourceLineNo">501</span><a name="line.501"></a>
<span class="sourceLineNo">502</span> /**<a name="line.502"></a>
<span class="sourceLineNo">503</span> * Removes a service from this Tracker object. The specified service will be removed from this Tracker object. If the specified service was being tracked then the<a name="line.503"></a>
<span class="sourceLineNo">504</span> * TrackerCustomizer.removedService method will be called for that service.<a name="line.504"></a>
<span class="sourceLineNo">505</span> * @param reference the Reference to the service to be removed.<a name="line.505"></a>
<span class="sourceLineNo">506</span> */<a name="line.506"></a>
<span class="sourceLineNo">507</span> public void remove(ServiceReference reference) {<a name="line.507"></a>
<span class="sourceLineNo">508</span> Tracked tracked = this.m_tracked; // use local var since we are not synchronized<a name="line.508"></a>
<span class="sourceLineNo">509</span> if (tracked == null) { /* if Tracker is not open */<a name="line.509"></a>
<span class="sourceLineNo">510</span> return;<a name="line.510"></a>
<span class="sourceLineNo">511</span> }<a name="line.511"></a>
<span class="sourceLineNo">512</span> tracked.untrack(reference);<a name="line.512"></a>
<span class="sourceLineNo">513</span> }<a name="line.513"></a>
<span class="sourceLineNo">514</span><a name="line.514"></a>
<span class="sourceLineNo">515</span> /**<a name="line.515"></a>
<span class="sourceLineNo">516</span> * Returns the number of services being tracked by this Tracker object.<a name="line.516"></a>
<span class="sourceLineNo">517</span> * @return the Number of services being tracked.<a name="line.517"></a>
<span class="sourceLineNo">518</span> */<a name="line.518"></a>
<span class="sourceLineNo">519</span> public int size() {<a name="line.519"></a>
<span class="sourceLineNo">520</span> Tracked tracked = this.m_tracked; //use local var since we are not synchronized<a name="line.520"></a>
<span class="sourceLineNo">521</span> if (tracked == null) { /* if Tracker is not open */<a name="line.521"></a>
<span class="sourceLineNo">522</span> return 0;<a name="line.522"></a>
<span class="sourceLineNo">523</span> }<a name="line.523"></a>
<span class="sourceLineNo">524</span> return tracked.size();<a name="line.524"></a>
<span class="sourceLineNo">525</span> }<a name="line.525"></a>
<span class="sourceLineNo">526</span><a name="line.526"></a>
<span class="sourceLineNo">527</span> /**<a name="line.527"></a>
<span class="sourceLineNo">528</span> * Inner class to track services. If a Tracker object is reused (closed then reopened), then a new Tracked object is used. This class is a hashtable mapping ServiceReference object -&gt; customized Object. This<a name="line.528"></a>
<span class="sourceLineNo">529</span> * class is the ServiceListener object for the tracker. This class is used to synchronize access to the tracked services. This is not a public class. It is only for use by the implementation of the Tracker<a name="line.529"></a>
<span class="sourceLineNo">530</span> * class.<a name="line.530"></a>
<span class="sourceLineNo">531</span> */<a name="line.531"></a>
<span class="sourceLineNo">532</span> class Tracked extends HashMap&lt;ServiceReference, Object&gt; implements ServiceListener {<a name="line.532"></a>
<span class="sourceLineNo">533</span><a name="line.533"></a>
<span class="sourceLineNo">534</span> /**<a name="line.534"></a>
<span class="sourceLineNo">535</span> * The list of ServiceReferences in the process of being added. This is used to deal with nesting of ServiceEvents. Since ServiceEvents are synchronously delivered, ServiceEvents can be nested. For example, when processing the adding of a service<a name="line.535"></a>
<span class="sourceLineNo">536</span> * and the customizer causes the service to be unregistered, notification to the nested call to untrack that the service was unregistered can be made to the track method. Since the ArrayList implementation is not synchronized, all access to<a name="line.536"></a>
<span class="sourceLineNo">537</span> * this list must be protected by the same synchronized object for thread safety.<a name="line.537"></a>
<span class="sourceLineNo">538</span> */<a name="line.538"></a>
<span class="sourceLineNo">539</span> private List&lt;ServiceReference&gt; m_adding;<a name="line.539"></a>
<span class="sourceLineNo">540</span><a name="line.540"></a>
<span class="sourceLineNo">541</span> /**<a name="line.541"></a>
<span class="sourceLineNo">542</span> * &lt;code&gt;true&lt;/code&gt; if the tracked object is closed. This field is volatile because it is set by one thread and read by another.<a name="line.542"></a>
<span class="sourceLineNo">543</span> */<a name="line.543"></a>
<span class="sourceLineNo">544</span> private volatile boolean m_closed;<a name="line.544"></a>
<span class="sourceLineNo">545</span><a name="line.545"></a>
<span class="sourceLineNo">546</span> /**<a name="line.546"></a>
<span class="sourceLineNo">547</span> * The Initial list of ServiceReferences for the tracker. This is used to correctly process the initial services which could become unregistered before they are tracked. This is necessary since the initial set of tracked services are not<a name="line.547"></a>
<span class="sourceLineNo">548</span> * "announced" by ServiceEvents and therefore the ServiceEvent for unregistration could be delivered before we track the service. A service must not be in both the initial and adding lists at the same time. A service must be moved from the<a name="line.548"></a>
<span class="sourceLineNo">549</span> * initial list to the adding list "atomically" before we begin tracking it. Since the LinkedList implementation is not synchronized, all access to this list must be protected by the same synchronized object for thread safety.<a name="line.549"></a>
<span class="sourceLineNo">550</span> */<a name="line.550"></a>
<span class="sourceLineNo">551</span> private List&lt;ServiceReference&gt; m_initial;<a name="line.551"></a>
<span class="sourceLineNo">552</span><a name="line.552"></a>
<span class="sourceLineNo">553</span> /**<a name="line.553"></a>
<span class="sourceLineNo">554</span> * Tracked constructor.<a name="line.554"></a>
<span class="sourceLineNo">555</span> */<a name="line.555"></a>
<span class="sourceLineNo">556</span> protected Tracked() {<a name="line.556"></a>
<span class="sourceLineNo">557</span> super();<a name="line.557"></a>
<span class="sourceLineNo">558</span> m_closed = false;<a name="line.558"></a>
<span class="sourceLineNo">559</span> m_adding = new ArrayList&lt;ServiceReference&gt;(6);<a name="line.559"></a>
<span class="sourceLineNo">560</span> m_initial = new LinkedList&lt;ServiceReference&gt;();<a name="line.560"></a>
<span class="sourceLineNo">561</span> }<a name="line.561"></a>
<span class="sourceLineNo">562</span><a name="line.562"></a>
<span class="sourceLineNo">563</span> /**<a name="line.563"></a>
<span class="sourceLineNo">564</span> * Sets initial list of services into tracker before ServiceEvents begin to be received. This method must be called from Tracker.open while synchronized on this object in the same synchronized block as the addServiceListener call.<a name="line.564"></a>
<span class="sourceLineNo">565</span> * @param references The initial list of services to be tracked.<a name="line.565"></a>
<span class="sourceLineNo">566</span> */<a name="line.566"></a>
<span class="sourceLineNo">567</span> protected void setInitialServices(ServiceReference[] references) {<a name="line.567"></a>
<span class="sourceLineNo">568</span> if (references == null) { return; }<a name="line.568"></a>
<span class="sourceLineNo">569</span> int size = references.length;<a name="line.569"></a>
<span class="sourceLineNo">570</span> m_initial.addAll(Arrays.asList(references).subList(0, size));<a name="line.570"></a>
<span class="sourceLineNo">571</span> }<a name="line.571"></a>
<span class="sourceLineNo">572</span><a name="line.572"></a>
<span class="sourceLineNo">573</span> /**<a name="line.573"></a>
<span class="sourceLineNo">574</span> * Tracks the initial list of services. This is called after ServiceEvents can begin to be received. This method must be called from Tracker.open while not synchronized on this object after the addServiceListener call.<a name="line.574"></a>
<span class="sourceLineNo">575</span> */<a name="line.575"></a>
<span class="sourceLineNo">576</span> protected void trackInitialServices() {<a name="line.576"></a>
<span class="sourceLineNo">577</span> while (true) {<a name="line.577"></a>
<span class="sourceLineNo">578</span> ServiceReference reference;<a name="line.578"></a>
<span class="sourceLineNo">579</span> synchronized (this) {<a name="line.579"></a>
<span class="sourceLineNo">580</span> if (m_initial.isEmpty()) { // if there are no more initial services<a name="line.580"></a>
<span class="sourceLineNo">581</span> return; // we are done<a name="line.581"></a>
<span class="sourceLineNo">582</span> }<a name="line.582"></a>
<span class="sourceLineNo">583</span><a name="line.583"></a>
<span class="sourceLineNo">584</span> // move the first service from the initial list to the adding list within this synchronized block.<a name="line.584"></a>
<span class="sourceLineNo">585</span> reference = (ServiceReference) ((LinkedList) m_initial).removeFirst();<a name="line.585"></a>
<span class="sourceLineNo">586</span> if (this.containsKey(reference)) { //Check if the reference is already tracked.<a name="line.586"></a>
<span class="sourceLineNo">587</span> //if we are already tracking this service<a name="line.587"></a>
<span class="sourceLineNo">588</span> continue; /* skip this service */<a name="line.588"></a>
<span class="sourceLineNo">589</span> }<a name="line.589"></a>
<span class="sourceLineNo">590</span> if (m_adding.contains(reference)) {<a name="line.590"></a>
<span class="sourceLineNo">591</span> // if this service is already in the process of being added.<a name="line.591"></a>
<span class="sourceLineNo">592</span> continue; // skip this service<a name="line.592"></a>
<span class="sourceLineNo">593</span> }<a name="line.593"></a>
<span class="sourceLineNo">594</span> m_adding.add(reference);<a name="line.594"></a>
<span class="sourceLineNo">595</span> }<a name="line.595"></a>
<span class="sourceLineNo">596</span> trackAdding(reference); // Begin tracking it. We call trackAdding since we have already put the reference in the adding list.<a name="line.596"></a>
<span class="sourceLineNo">597</span> }<a name="line.597"></a>
<span class="sourceLineNo">598</span> }<a name="line.598"></a>
<span class="sourceLineNo">599</span><a name="line.599"></a>
<span class="sourceLineNo">600</span> /**<a name="line.600"></a>
<span class="sourceLineNo">601</span> * Called by the owning Tracker object when it is closed.<a name="line.601"></a>
<span class="sourceLineNo">602</span> */<a name="line.602"></a>
<span class="sourceLineNo">603</span> protected void close() {<a name="line.603"></a>
<span class="sourceLineNo">604</span> m_closed = true;<a name="line.604"></a>
<span class="sourceLineNo">605</span> }<a name="line.605"></a>
<span class="sourceLineNo">606</span><a name="line.606"></a>
<span class="sourceLineNo">607</span> /**<a name="line.607"></a>
<span class="sourceLineNo">608</span> * ServiceListener method for the Tracker class. This method must NOT be synchronized to avoid deadlock potential.<a name="line.608"></a>
<span class="sourceLineNo">609</span> * @param event the ServiceEvent object from the framework.<a name="line.609"></a>
<span class="sourceLineNo">610</span> */<a name="line.610"></a>
<span class="sourceLineNo">611</span> public void serviceChanged(ServiceEvent event) {<a name="line.611"></a>
<span class="sourceLineNo">612</span> //Check if we had a delayed call (which could happen when we close).<a name="line.612"></a>
<span class="sourceLineNo">613</span> if (m_closed) { return; }<a name="line.613"></a>
<span class="sourceLineNo">614</span> ServiceReference reference = event.getServiceReference();<a name="line.614"></a>
<span class="sourceLineNo">615</span><a name="line.615"></a>
<span class="sourceLineNo">616</span> switch (event.getType()) {<a name="line.616"></a>
<span class="sourceLineNo">617</span> case ServiceEvent.REGISTERED:<a name="line.617"></a>
<span class="sourceLineNo">618</span> case ServiceEvent.MODIFIED:<a name="line.618"></a>
<span class="sourceLineNo">619</span> if (m_listenerFilter == null) { // user supplied filter<a name="line.619"></a>
<span class="sourceLineNo">620</span> boolean match = true;<a name="line.620"></a>
<span class="sourceLineNo">621</span> if (reference instanceof ServiceReferenceImpl) {<a name="line.621"></a>
<span class="sourceLineNo">622</span> // Can't use the match(ref) as it throw a class cast exception on Equinox.<a name="line.622"></a>
<span class="sourceLineNo">623</span> match = m_filter.match(((ServiceReferenceImpl) reference).getProperties());<a name="line.623"></a>
<span class="sourceLineNo">624</span> } else { // Non computed reference.<a name="line.624"></a>
<span class="sourceLineNo">625</span> match = m_filter.match(reference);<a name="line.625"></a>
<span class="sourceLineNo">626</span> }<a name="line.626"></a>
<span class="sourceLineNo">627</span> if (match) {<a name="line.627"></a>
<span class="sourceLineNo">628</span> track(reference); // Arrival<a name="line.628"></a>
<span class="sourceLineNo">629</span> } else {<a name="line.629"></a>
<span class="sourceLineNo">630</span> untrack(reference); // Departure<a name="line.630"></a>
<span class="sourceLineNo">631</span> }<a name="line.631"></a>
<span class="sourceLineNo">632</span> } else { // constructor supplied filter<a name="line.632"></a>
<span class="sourceLineNo">633</span> track(reference);<a name="line.633"></a>
<span class="sourceLineNo">634</span> }<a name="line.634"></a>
<span class="sourceLineNo">635</span> break;<a name="line.635"></a>
<span class="sourceLineNo">636</span> case ServiceEvent.UNREGISTERING:<a name="line.636"></a>
<span class="sourceLineNo">637</span> untrack(reference); // Departure<a name="line.637"></a>
<span class="sourceLineNo">638</span> break;<a name="line.638"></a>
<span class="sourceLineNo">639</span> default:<a name="line.639"></a>
<span class="sourceLineNo">640</span> break;<a name="line.640"></a>
<span class="sourceLineNo">641</span> }<a name="line.641"></a>
<span class="sourceLineNo">642</span> }<a name="line.642"></a>
<span class="sourceLineNo">643</span><a name="line.643"></a>
<span class="sourceLineNo">644</span> /**<a name="line.644"></a>
<span class="sourceLineNo">645</span> * Begins to track the referenced service.<a name="line.645"></a>
<span class="sourceLineNo">646</span> * @param reference the Reference to a service to be tracked.<a name="line.646"></a>
<span class="sourceLineNo">647</span> */<a name="line.647"></a>
<span class="sourceLineNo">648</span> protected void track(ServiceReference reference) {<a name="line.648"></a>
<span class="sourceLineNo">649</span> Object object;<a name="line.649"></a>
<span class="sourceLineNo">650</span> boolean alreadyTracked;<a name="line.650"></a>
<span class="sourceLineNo">651</span> synchronized (this) {<a name="line.651"></a>
<span class="sourceLineNo">652</span> alreadyTracked = this.containsKey(reference);<a name="line.652"></a>
<span class="sourceLineNo">653</span> object = this.get(reference);<a name="line.653"></a>
<span class="sourceLineNo">654</span> }<a name="line.654"></a>
<span class="sourceLineNo">655</span> if (alreadyTracked) { // we are already tracking the service<a name="line.655"></a>
<span class="sourceLineNo">656</span> if (object != null) { // If already get, invalidate the cache<a name="line.656"></a>
<span class="sourceLineNo">657</span> synchronized (this) {<a name="line.657"></a>
<span class="sourceLineNo">658</span> modified();<a name="line.658"></a>
<span class="sourceLineNo">659</span> }<a name="line.659"></a>
<span class="sourceLineNo">660</span> }<a name="line.660"></a>
<span class="sourceLineNo">661</span> // Call customizer outside of synchronized region<a name="line.661"></a>
<span class="sourceLineNo">662</span> m_customizer.modifiedService(reference, object);<a name="line.662"></a>
<span class="sourceLineNo">663</span> return;<a name="line.663"></a>
<span class="sourceLineNo">664</span> }<a name="line.664"></a>
<span class="sourceLineNo">665</span> synchronized (this) {<a name="line.665"></a>
<span class="sourceLineNo">666</span> if (m_adding.contains(reference)) { // if this service is already in the process of being added.<a name="line.666"></a>
<span class="sourceLineNo">667</span> return;<a name="line.667"></a>
<span class="sourceLineNo">668</span> }<a name="line.668"></a>
<span class="sourceLineNo">669</span> m_adding.add(reference); // mark this service is being added<a name="line.669"></a>
<span class="sourceLineNo">670</span> }<a name="line.670"></a>
<span class="sourceLineNo">671</span><a name="line.671"></a>
<span class="sourceLineNo">672</span> trackAdding(reference); // call trackAdding now that we have put the reference in the adding list<a name="line.672"></a>
<span class="sourceLineNo">673</span> }<a name="line.673"></a>
<span class="sourceLineNo">674</span><a name="line.674"></a>
<span class="sourceLineNo">675</span> /**<a name="line.675"></a>
<span class="sourceLineNo">676</span> * Common logic to add a service to the tracker used by track and trackInitialServices.<a name="line.676"></a>
<span class="sourceLineNo">677</span> * The specified reference must have been placed in the adding list before calling this method.<a name="line.677"></a>
<span class="sourceLineNo">678</span> * @param reference the Reference to a service to be tracked.<a name="line.678"></a>
<span class="sourceLineNo">679</span> */<a name="line.679"></a>
<span class="sourceLineNo">680</span> private void trackAdding(ServiceReference reference) {<a name="line.680"></a>
<span class="sourceLineNo">681</span> boolean mustBeTracked = false;<a name="line.681"></a>
<span class="sourceLineNo">682</span> boolean becameUntracked = false;<a name="line.682"></a>
<span class="sourceLineNo">683</span> boolean mustCallAdded = false;<a name="line.683"></a>
<span class="sourceLineNo">684</span> //Call customizer outside of synchronized region<a name="line.684"></a>
<span class="sourceLineNo">685</span> try {<a name="line.685"></a>
<span class="sourceLineNo">686</span> mustBeTracked = m_customizer.addingService(reference);<a name="line.686"></a>
<span class="sourceLineNo">687</span> } finally {<a name="line.687"></a>
<span class="sourceLineNo">688</span> synchronized (this) {<a name="line.688"></a>
<span class="sourceLineNo">689</span> if (m_adding.remove(reference)) { // if the service was not untracked during the customizer callback<a name="line.689"></a>
<span class="sourceLineNo">690</span> if (mustBeTracked) {<a name="line.690"></a>
<span class="sourceLineNo">691</span> this.put(reference, null);<a name="line.691"></a>
<span class="sourceLineNo">692</span> modified();<a name="line.692"></a>
<span class="sourceLineNo">693</span> mustCallAdded = true;<a name="line.693"></a>
<span class="sourceLineNo">694</span> notifyAll(); // notify any waiters in waitForService<a name="line.694"></a>
<span class="sourceLineNo">695</span> }<a name="line.695"></a>
<span class="sourceLineNo">696</span> } else {<a name="line.696"></a>
<span class="sourceLineNo">697</span> becameUntracked = true;<a name="line.697"></a>
<span class="sourceLineNo">698</span> // If already get during the customizer callback<a name="line.698"></a>
<span class="sourceLineNo">699</span> ungetService(reference);<a name="line.699"></a>
<span class="sourceLineNo">700</span> modified();<a name="line.700"></a>
<span class="sourceLineNo">701</span> }<a name="line.701"></a>
<span class="sourceLineNo">702</span> }<a name="line.702"></a>
<span class="sourceLineNo">703</span> }<a name="line.703"></a>
<span class="sourceLineNo">704</span><a name="line.704"></a>
<span class="sourceLineNo">705</span> // Call customizer outside of synchronized region<a name="line.705"></a>
<span class="sourceLineNo">706</span> if (becameUntracked) {<a name="line.706"></a>
<span class="sourceLineNo">707</span> // The service became untracked during the customizer callback.<a name="line.707"></a>
<span class="sourceLineNo">708</span> m_customizer.removedService(reference, null);<a name="line.708"></a>
<span class="sourceLineNo">709</span> } else {<a name="line.709"></a>
<span class="sourceLineNo">710</span> if (mustCallAdded) {<a name="line.710"></a>
<span class="sourceLineNo">711</span> m_customizer.addedService(reference);<a name="line.711"></a>
<span class="sourceLineNo">712</span> }<a name="line.712"></a>
<span class="sourceLineNo">713</span> }<a name="line.713"></a>
<span class="sourceLineNo">714</span> }<a name="line.714"></a>
<span class="sourceLineNo">715</span><a name="line.715"></a>
<span class="sourceLineNo">716</span> /**<a name="line.716"></a>
<span class="sourceLineNo">717</span> * Discontinues tracking the referenced service.<a name="line.717"></a>
<span class="sourceLineNo">718</span> * @param reference the Reference to the tracked service.<a name="line.718"></a>
<span class="sourceLineNo">719</span> */<a name="line.719"></a>
<span class="sourceLineNo">720</span> protected void untrack(ServiceReference reference) {<a name="line.720"></a>
<span class="sourceLineNo">721</span> Object object;<a name="line.721"></a>
<span class="sourceLineNo">722</span> synchronized (this) {<a name="line.722"></a>
<span class="sourceLineNo">723</span> if (m_initial.remove(reference)) { // if this service is already in the list of initial references to process<a name="line.723"></a>
<span class="sourceLineNo">724</span> return; // we have removed it from the list and it will not be processed<a name="line.724"></a>
<span class="sourceLineNo">725</span> }<a name="line.725"></a>
<span class="sourceLineNo">726</span><a name="line.726"></a>
<span class="sourceLineNo">727</span> if (m_adding.remove(reference)) { // if the service is in the process of being added<a name="line.727"></a>
<span class="sourceLineNo">728</span> return; // in case the service is untracked while in the process of adding<a name="line.728"></a>
<span class="sourceLineNo">729</span> }<a name="line.729"></a>
<span class="sourceLineNo">730</span><a name="line.730"></a>
<span class="sourceLineNo">731</span> boolean isTraked = this.containsKey(reference); // Check if we was tracking the reference<a name="line.731"></a>
<span class="sourceLineNo">732</span> object = this.remove(reference); // must remove from tracker before calling customizer callback<a name="line.732"></a>
<span class="sourceLineNo">733</span><a name="line.733"></a>
<span class="sourceLineNo">734</span> if (!isTraked) { return; }<a name="line.734"></a>
<span class="sourceLineNo">735</span> modified();<a name="line.735"></a>
<span class="sourceLineNo">736</span> }<a name="line.736"></a>
<span class="sourceLineNo">737</span> // Call customizer outside of synchronized region and only if we are not closed<a name="line.737"></a>
<span class="sourceLineNo">738</span> if (! m_closed) {<a name="line.738"></a>
<span class="sourceLineNo">739</span> m_customizer.removedService(reference, object);<a name="line.739"></a>
<span class="sourceLineNo">740</span> }<a name="line.740"></a>
<span class="sourceLineNo">741</span> // If the customizer throws an unchecked exception, it is safe to let it propagate<a name="line.741"></a>
<span class="sourceLineNo">742</span> }<a name="line.742"></a>
<span class="sourceLineNo">743</span><a name="line.743"></a>
<span class="sourceLineNo">744</span> /**<a name="line.744"></a>
<span class="sourceLineNo">745</span> * Called by the Tracked object whenever the set of tracked services is modified. Increments the tracking count and clears the cache.<a name="line.745"></a>
<span class="sourceLineNo">746</span> * This method must not be synchronized since it is called by Tracked while Tracked is synchronized. We don't want synchronization interactions between the ServiceListener thread and the user thread.<a name="line.746"></a>
<span class="sourceLineNo">747</span> */<a name="line.747"></a>
<span class="sourceLineNo">748</span> void modified() {<a name="line.748"></a>
<span class="sourceLineNo">749</span> m_cachedReference = null; /* clear cached value */<a name="line.749"></a>
<span class="sourceLineNo">750</span> m_cachedService = null; /* clear cached value */<a name="line.750"></a>
<span class="sourceLineNo">751</span> }<a name="line.751"></a>
<span class="sourceLineNo">752</span> }<a name="line.752"></a>
<span class="sourceLineNo">753</span>}<a name="line.753"></a>
</pre>
</div>
</body>
</html>