Clover Coverage Report - JmDNS 3.4.1
Coverage timestamp: Thu Aug 25 2011 13:06:33 CEST
../../../img/srcFileCovDistChart5.png 47% of files have more coverage
77   286   36   4.81
36   157   0.47   5.33
16     2.25  
3    
 
  ListenerStatus       Line # 24 8 0% 6 4 71.4% 0.71428573
  ListenerStatus.ServiceListenerStatus       Line # 26 50 0% 23 32 62.8% 0.627907
  ListenerStatus.ServiceTypeListenerStatus       Line # 153 19 0% 7 29 0% 0.0
 
  (17)
 
1    /**
2    *
3    */
4    package javax.jmdns.impl;
5   
6    import java.util.EventListener;
7    import java.util.concurrent.ConcurrentHashMap;
8    import java.util.concurrent.ConcurrentMap;
9    import java.util.logging.Logger;
10   
11    import javax.jmdns.JmDNS;
12    import javax.jmdns.ServiceEvent;
13    import javax.jmdns.ServiceInfo;
14    import javax.jmdns.ServiceListener;
15    import javax.jmdns.ServiceTypeListener;
16   
17    /**
18    * This class track the status of listener.<br/>
19    * The main purpose of this class is to collapse consecutive events so that we can guarantee the correct call back sequence.
20    *
21    * @param <T>
22    * listener type
23    */
 
24    public class ListenerStatus<T extends EventListener> {
25   
 
26    public static class ServiceListenerStatus extends ListenerStatus<ServiceListener> {
27    private static Logger logger = Logger.getLogger(ServiceListenerStatus.class.getName());
28   
29    private final ConcurrentMap<String, ServiceInfo> _addedServices;
30   
31    /**
32    * @param listener
33    * listener being tracked.
34    * @param synch
35    * true if that listener can be called asynchronously
36    */
 
37  42 toggle public ServiceListenerStatus(ServiceListener listener, boolean synch) {
38  42 super(listener, synch);
39  42 _addedServices = new ConcurrentHashMap<String, ServiceInfo>(32);
40    }
41   
42    /**
43    * A service has been added.<br/>
44    * <b>Note:</b>This event is only the service added event. The service info associated with this event does not include resolution information.<br/>
45    * To get the full resolved information you need to listen to {@link #serviceResolved(ServiceEvent)} or call {@link JmDNS#getServiceInfo(String, String, long)}
46    *
47    * <pre>
48    * ServiceInfo info = event.getDNS().getServiceInfo(event.getType(), event.getName())
49    * </pre>
50    * <p>
51    * Please note that service resolution may take a few second to resolve.
52    * </p>
53    *
54    * @param event
55    * The ServiceEvent providing the name and fully qualified type of the service.
56    */
 
57  26 toggle void serviceAdded(ServiceEvent event) {
58  26 String qualifiedName = event.getName() + "." + event.getType();
59  26 if (null == _addedServices.putIfAbsent(qualifiedName, event.getInfo().clone())) {
60  26 this.getListener().serviceAdded(event);
61  26 ServiceInfo info = event.getInfo();
62  26 if ((info != null) && (info.hasData())) {
63  1 this.getListener().serviceResolved(event);
64    }
65    } else {
66  0 logger.finer("Service Added called for a service already added: " + event);
67    }
68    }
69   
70    /**
71    * A service has been removed.
72    *
73    * @param event
74    * The ServiceEvent providing the name and fully qualified type of the service.
75    */
 
76  5 toggle void serviceRemoved(ServiceEvent event) {
77  5 String qualifiedName = event.getName() + "." + event.getType();
78  5 if (_addedServices.remove(qualifiedName, _addedServices.get(qualifiedName))) {
79  5 this.getListener().serviceRemoved(event);
80    } else {
81  0 logger.finer("Service Removed called for a service already removed: " + event);
82    }
83    }
84   
85    /**
86    * A service has been resolved. Its details are now available in the ServiceInfo record.<br/>
87    * <b>Note:</b>This call back will never be called if the service does not resolve.<br/>
88    *
89    * @param event
90    * The ServiceEvent providing the name, the fully qualified type of the service, and the service info record.
91    */
 
92  40 toggle synchronized void serviceResolved(ServiceEvent event) {
93  40 ServiceInfo info = event.getInfo();
94  40 if ((info != null) && (info.hasData())) {
95  40 String qualifiedName = event.getName() + "." + event.getType();
96  40 ServiceInfo previousServiceInfo = _addedServices.get(qualifiedName);
97  40 if (!_sameInfo(info, previousServiceInfo)) {
98  33 if (null == previousServiceInfo) {
99  0 if (null == _addedServices.putIfAbsent(qualifiedName, info.clone())) {
100  0 this.getListener().serviceResolved(event);
101    }
102    } else {
103  33 if (_addedServices.replace(qualifiedName, previousServiceInfo, info.clone())) {
104  33 this.getListener().serviceResolved(event);
105    }
106    }
107    } else {
108  7 logger.finer("Service Resolved called for a service already resolved: " + event);
109    }
110    } else {
111  0 logger.warning("Service Resolved called for an unresolved event: " + event);
112   
113    }
114    }
115   
 
116  40 toggle private static final boolean _sameInfo(ServiceInfo info, ServiceInfo lastInfo) {
117  40 if (info == null) return false;
118  40 if (lastInfo == null) return false;
119  40 if (!info.equals(lastInfo)) return false;
120  40 byte[] text = info.getTextBytes();
121  40 byte[] lastText = lastInfo.getTextBytes();
122  18 if (text.length != lastText.length) return false;
123  281 for (int i = 0; i < text.length; i++) {
124  15 if (text[i] != lastText[i]) return false;
125    }
126  7 return true;
127    }
128   
129    /*
130    * (non-Javadoc)
131    * @see java.lang.Object#toString()
132    */
 
133  0 toggle @Override
134    public String toString() {
135  0 StringBuilder aLog = new StringBuilder(2048);
136  0 aLog.append("[Status for ");
137  0 aLog.append(this.getListener().toString());
138  0 if (_addedServices.isEmpty()) {
139  0 aLog.append(" no type event ");
140    } else {
141  0 aLog.append(" (");
142  0 for (String service : _addedServices.keySet()) {
143  0 aLog.append(service + ", ");
144    }
145  0 aLog.append(") ");
146    }
147  0 aLog.append("]");
148  0 return aLog.toString();
149    }
150   
151    }
152   
 
153    public static class ServiceTypeListenerStatus extends ListenerStatus<ServiceTypeListener> {
154    private static Logger logger = Logger.getLogger(ServiceTypeListenerStatus.class.getName());
155   
156    private final ConcurrentMap<String, String> _addedTypes;
157   
158    /**
159    * @param listener
160    * listener being tracked.
161    * @param synch
162    * true if that listener can be called asynchronously
163    */
 
164  0 toggle public ServiceTypeListenerStatus(ServiceTypeListener listener, boolean synch) {
165  0 super(listener, synch);
166  0 _addedTypes = new ConcurrentHashMap<String, String>(32);
167    }
168   
169    /**
170    * A new service type was discovered.
171    *
172    * @param event
173    * The service event providing the fully qualified type of the service.
174    */
 
175  0 toggle void serviceTypeAdded(ServiceEvent event) {
176  0 if (null == _addedTypes.putIfAbsent(event.getType(), event.getType())) {
177  0 this.getListener().serviceTypeAdded(event);
178    } else {
179  0 logger.finest("Service Type Added called for a service type already added: " + event);
180    }
181    }
182   
183    /**
184    * A new subtype for the service type was discovered.
185    *
186    * <pre>
187    * &lt;sub&gt;._sub.&lt;app&gt;.&lt;protocol&gt;.&lt;servicedomain&gt;.&lt;parentdomain&gt;.
188    * </pre>
189    *
190    * @param event
191    * The service event providing the fully qualified type of the service with subtype.
192    */
 
193  0 toggle void subTypeForServiceTypeAdded(ServiceEvent event) {
194  0 if (null == _addedTypes.putIfAbsent(event.getType(), event.getType())) {
195  0 this.getListener().subTypeForServiceTypeAdded(event);
196    } else {
197  0 logger.finest("Service Sub Type Added called for a service sub type already added: " + event);
198    }
199    }
200   
201    /*
202    * (non-Javadoc)
203    * @see java.lang.Object#toString()
204    */
 
205  0 toggle @Override
206    public String toString() {
207  0 StringBuilder aLog = new StringBuilder(2048);
208  0 aLog.append("[Status for ");
209  0 aLog.append(this.getListener().toString());
210  0 if (_addedTypes.isEmpty()) {
211  0 aLog.append(" no type event ");
212    } else {
213  0 aLog.append(" (");
214  0 for (String type : _addedTypes.keySet()) {
215  0 aLog.append(type + ", ");
216    }
217  0 aLog.append(") ");
218    }
219  0 aLog.append("]");
220  0 return aLog.toString();
221    }
222   
223    }
224   
225    public final static boolean SYNCHONEOUS = true;
226    public final static boolean ASYNCHONEOUS = false;
227   
228    private final T _listener;
229   
230    private final boolean _synch;
231   
232    /**
233    * @param listener
234    * listener being tracked.
235    * @param synch
236    * true if that listener can be called asynchronously
237    */
 
238  42 toggle public ListenerStatus(T listener, boolean synch) {
239  42 super();
240  42 _listener = listener;
241  42 _synch = synch;
242    }
243   
244    /**
245    * @return the listener
246    */
 
247  99 toggle public T getListener() {
248  99 return _listener;
249    }
250   
251    /**
252    * Return <cod>true</code> if the listener must be called synchronously.
253    *
254    * @return the synch
255    */
 
256  23 toggle public boolean isSynchronous() {
257  23 return _synch;
258    }
259   
260    /*
261    * (non-Javadoc)
262    * @see java.lang.Object#hashCode()
263    */
 
264  0 toggle @Override
265    public int hashCode() {
266  0 return this.getListener().hashCode();
267    }
268   
269    /*
270    * (non-Javadoc)
271    * @see java.lang.Object#equals(java.lang.Object)
272    */
 
273  17 toggle @Override
274    public boolean equals(Object obj) {
275  17 return (obj instanceof ListenerStatus) && this.getListener().equals(((ListenerStatus<?>) obj).getListener());
276    }
277   
278    /*
279    * (non-Javadoc)
280    * @see java.lang.Object#toString()
281    */
 
282  0 toggle @Override
283    public String toString() {
284  0 return "[Status for " + this.getListener().toString() + "]";
285    }
286    }