13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl;
53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.EventListener;
73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ConcurrentHashMap;
83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.concurrent.ConcurrentMap;
93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger;
103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.JmDNS;
123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceEvent;
133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo;
143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceListener;
153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceTypeListener;
163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This class track the status of listener.<br/>
193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * The main purpose of this class is to collapse consecutive events so that we can guarantee the correct call back sequence.
203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param <T>
223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *            listener type
233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic class ListenerStatus<T extends EventListener> {
253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class ServiceListenerStatus extends ListenerStatus<ServiceListener> {
273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static Logger                            logger = Logger.getLogger(ServiceListenerStatus.class.getName());
283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final ConcurrentMap<String, ServiceInfo> _addedServices;
303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param listener
333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            listener being tracked.
343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param synch
353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            true if that listener can be called asynchronously
363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceListenerStatus(ServiceListener listener, boolean synch) {
383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(listener, synch);
393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _addedServices = new ConcurrentHashMap<String, ServiceInfo>(32);
403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * A service has been added.<br/>
443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * <b>Note:</b>This event is only the service added event. The service info associated with this event does not include resolution information.<br/>
453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * To get the full resolved information you need to listen to {@link #serviceResolved(ServiceEvent)} or call {@link JmDNS#getServiceInfo(String, String, long)}
463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * <pre>
483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *  ServiceInfo info = event.getDNS().getServiceInfo(event.getType(), event.getName())
493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * </pre>
503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * <p>
513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * Please note that service resolution may take a few second to resolve.
523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * </p>
533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param event
553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            The ServiceEvent providing the name and fully qualified type of the service.
563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void serviceAdded(ServiceEvent event) {
583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String qualifiedName = event.getName() + "." + event.getType();
593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (null == _addedServices.putIfAbsent(qualifiedName, event.getInfo().clone())) {
603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this.getListener().serviceAdded(event);
613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                ServiceInfo info = event.getInfo();
623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if ((info != null) && (info.hasData())) {
633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    this.getListener().serviceResolved(event);
643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.finer("Service Added called for a service already added: " + event);
673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * A service has been removed.
723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param event
743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            The ServiceEvent providing the name and fully qualified type of the service.
753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void serviceRemoved(ServiceEvent event) {
773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String qualifiedName = event.getName() + "." + event.getType();
783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (_addedServices.remove(qualifiedName, _addedServices.get(qualifiedName))) {
793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this.getListener().serviceRemoved(event);
803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.finer("Service Removed called for a service already removed: " + event);
823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * A service has been resolved. Its details are now available in the ServiceInfo record.<br/>
873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * <b>Note:</b>This call back will never be called if the service does not resolve.<br/>
883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param event
903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            The ServiceEvent providing the name, the fully qualified type of the service, and the service info record.
913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        synchronized void serviceResolved(ServiceEvent event) {
933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ServiceInfo info = event.getInfo();
943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((info != null) && (info.hasData())) {
953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                String qualifiedName = event.getName() + "." + event.getType();
963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                ServiceInfo previousServiceInfo = _addedServices.get(qualifiedName);
973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (!_sameInfo(info, previousServiceInfo)) {
983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (null == previousServiceInfo) {
993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (null == _addedServices.putIfAbsent(qualifiedName, info.clone())) {
1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            this.getListener().serviceResolved(event);
1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    } else {
1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (_addedServices.replace(qualifiedName, previousServiceInfo, info.clone())) {
1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            this.getListener().serviceResolved(event);
1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    logger.finer("Service Resolved called for a service already resolved: " + event);
1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.warning("Service Resolved called for an unresolved event: " + event);
1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static final boolean _sameInfo(ServiceInfo info, ServiceInfo lastInfo) {
1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (info == null) return false;
1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (lastInfo == null) return false;
1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (!info.equals(lastInfo)) return false;
1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            byte[] text = info.getTextBytes();
1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            byte[] lastText = lastInfo.getTextBytes();
1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (text.length != lastText.length) return false;
1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (int i = 0; i < text.length; i++) {
1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (text[i] != lastText[i]) return false;
1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return true;
1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see java.lang.Object#toString()
1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public String toString() {
1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            StringBuilder aLog = new StringBuilder(2048);
1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append("[Status for ");
1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(this.getListener().toString());
1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (_addedServices.isEmpty()) {
1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aLog.append(" no type event ");
1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aLog.append(" (");
1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                for (String service : _addedServices.keySet()) {
1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    aLog.append(service + ", ");
1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aLog.append(") ");
1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append("]");
1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return aLog.toString();
1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static class ServiceTypeListenerStatus extends ListenerStatus<ServiceTypeListener> {
1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static Logger                       logger = Logger.getLogger(ServiceTypeListenerStatus.class.getName());
1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final ConcurrentMap<String, String> _addedTypes;
1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param listener
1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            listener being tracked.
1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param synch
1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            true if that listener can be called asynchronously
1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceTypeListenerStatus(ServiceTypeListener listener, boolean synch) {
1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super(listener, synch);
1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _addedTypes = new ConcurrentHashMap<String, String>(32);
1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * A new service type was discovered.
1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param event
1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            The service event providing the fully qualified type of the service.
1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void serviceTypeAdded(ServiceEvent event) {
1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (null == _addedTypes.putIfAbsent(event.getType(), event.getType())) {
1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this.getListener().serviceTypeAdded(event);
1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.finest("Service Type Added called for a service type already added: " + event);
1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * A new subtype for the service type was discovered.
1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * <pre>
1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * &lt;sub&gt;._sub.&lt;app&gt;.&lt;protocol&gt;.&lt;servicedomain&gt;.&lt;parentdomain&gt;.
1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * </pre>
1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *
1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param event
1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         *            The service event providing the fully qualified type of the service with subtype.
1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        void subTypeForServiceTypeAdded(ServiceEvent event) {
1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (null == _addedTypes.putIfAbsent(event.getType(), event.getType())) {
1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this.getListener().subTypeForServiceTypeAdded(event);
1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.finest("Service Sub Type Added called for a service sub type already added: " + event);
1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /*
2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * (non-Javadoc)
2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @see java.lang.Object#toString()
2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public String toString() {
2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            StringBuilder aLog = new StringBuilder(2048);
2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append("[Status for ");
2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append(this.getListener().toString());
2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (_addedTypes.isEmpty()) {
2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aLog.append(" no type event ");
2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aLog.append(" (");
2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                for (String type : _addedTypes.keySet()) {
2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    aLog.append(type + ", ");
2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                aLog.append(") ");
2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            aLog.append("]");
2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return aLog.toString();
2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public final static boolean SYNCHONEOUS  = true;
2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public final static boolean ASYNCHONEOUS = false;
2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final T             _listener;
2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final boolean       _synch;
2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param listener
2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            listener being tracked.
2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param synch
2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            true if that listener can be called asynchronously
2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ListenerStatus(T listener, boolean synch) {
2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        super();
2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _listener = listener;
2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _synch = synch;
2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return the listener
2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public T getListener() {
2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _listener;
2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Return <cod>true</code> if the listener must be called synchronously.
2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return the synch
2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isSynchronous() {
2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _synch;
2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see java.lang.Object#hashCode()
2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public int hashCode() {
2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getListener().hashCode();
2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see java.lang.Object#equals(java.lang.Object)
2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean equals(Object obj) {
2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (obj instanceof ListenerStatus) && this.getListener().equals(((ListenerStatus<?>) obj).getListener());
2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see java.lang.Object#toString()
2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String toString() {
2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return "[Status for " + this.getListener().toString() + "]";
2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman}
287