13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Copyright 2003-2005 Arthur van Hoff, Rick Blair
23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Licensed under Apache License version 2.0
33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Original license LGPL
43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl;
63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.ByteArrayOutputStream;
83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException;
93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.OutputStream;
103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet4Address;
113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.Inet6Address;
123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.net.InetAddress;
133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.ArrayList;
143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Collection;
153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Collections;
163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Enumeration;
173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.HashMap;
183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Hashtable;
193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.LinkedHashSet;
203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.List;
213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Map;
223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Set;
233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.Vector;
243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Level;
253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger;
263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceEvent;
283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo;
293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSRecord.Pointer;
303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSRecord.Service;
313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSRecord.Text;
323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordClass;
333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSRecordType;
343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSState;
353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.tasks.DNSTask;
363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/**
383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * JmDNS service information.
393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman *
403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Arthur van Hoff, Jeff Sonstein, Werner Randelshofer
413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */
423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic class ServiceInfoImpl extends ServiceInfo implements DNSListener, DNSStatefulObject {
433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static Logger           logger = Logger.getLogger(ServiceInfoImpl.class.getName());
443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private String                  _domain;
463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private String                  _protocol;
473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private String                  _application;
483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private String                  _name;
493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private String                  _subtype;
503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private String                  _server;
513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private int                     _port;
523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private int                     _weight;
533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private int                     _priority;
543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private byte                    _text[];
553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private Map<String, byte[]>     _props;
563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final Set<Inet4Address> _ipv4Addresses;
573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final Set<Inet6Address> _ipv6Addresses;
583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private transient String        _key;
603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private boolean                 _persistent;
623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private boolean                 _needTextAnnouncing;
633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final ServiceInfoState  _state;
653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private Delegate                _delegate;
673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static interface Delegate {
693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public void textValueUpdated(ServiceInfo target, byte[] value);
713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final static class ServiceInfoState extends DNSStatefulObject.DefaultImplementation {
753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private static final long     serialVersionUID = 1104131034952196820L;
773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        private final ServiceInfoImpl _info;
793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        /**
813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         * @param info
823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman         */
833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public ServiceInfoState(ServiceInfoImpl info) {
843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super();
853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _info = info;
863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protected void setTask(DNSTask task) {
903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.setTask(task);
913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((this._task == null) && _info.needTextAnnouncing()) {
923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this.lock();
933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                try {
943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if ((this._task == null) && _info.needTextAnnouncing()) {
953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (this._state.isAnnounced()) {
963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            this.setState(DNSState.ANNOUNCING_1);
973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            if (this.getDns() != null) {
983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                                this.getDns().startAnnouncer();
993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            }
1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _info.setNeedTextAnnouncing(false);
1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } finally {
1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    this.unlock();
1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        @Override
1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        public void setDns(JmDNSImpl dns) {
1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            super.setDns(dns);
1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param type
1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param name
1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param subtype
1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param port
1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param weight
1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param priority
1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param persistent
1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param text
1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#create(String, String, int, int, int, String)
1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfoImpl(String type, String name, String subtype, int port, int weight, int priority, boolean persistent, String text) {
1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this(ServiceInfoImpl.decodeQualifiedNameMap(type, name, subtype), port, weight, priority, persistent, (byte[]) null);
1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _server = text;
1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ByteArrayOutputStream out = new ByteArrayOutputStream(text.length());
1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            writeUTF(out, text);
1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._text = out.toByteArray();
1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (IOException e) {
1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            throw new RuntimeException("unexpected exception: " + e);
1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param type
1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param name
1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param subtype
1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param port
1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param weight
1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param priority
1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param persistent
1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param props
1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#create(String, String, int, int, int, Map)
1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfoImpl(String type, String name, String subtype, int port, int weight, int priority, boolean persistent, Map<String, ?> props) {
1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this(ServiceInfoImpl.decodeQualifiedNameMap(type, name, subtype), port, weight, priority, persistent, textFromProperties(props));
1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param type
1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param name
1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param subtype
1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param port
1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param weight
1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param priority
1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param persistent
1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param text
1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#create(String, String, int, int, int, byte[])
1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfoImpl(String type, String name, String subtype, int port, int weight, int priority, boolean persistent, byte text[]) {
1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this(ServiceInfoImpl.decodeQualifiedNameMap(type, name, subtype), port, weight, priority, persistent, text);
1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfoImpl(Map<Fields, String> qualifiedNameMap, int port, int weight, int priority, boolean persistent, Map<String, ?> props) {
1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this(qualifiedNameMap, port, weight, priority, persistent, textFromProperties(props));
1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    ServiceInfoImpl(Map<Fields, String> qualifiedNameMap, int port, int weight, int priority, boolean persistent, String text) {
1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this(qualifiedNameMap, port, weight, priority, persistent, (byte[]) null);
1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _server = text;
1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        try {
1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            ByteArrayOutputStream out = new ByteArrayOutputStream(text.length());
1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            writeUTF(out, text);
1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._text = out.toByteArray();
1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } catch (IOException e) {
1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            throw new RuntimeException("unexpected exception: " + e);
1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    ServiceInfoImpl(Map<Fields, String> qualifiedNameMap, int port, int weight, int priority, boolean persistent, byte text[]) {
1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<Fields, String> map = ServiceInfoImpl.checkQualifiedNameMap(qualifiedNameMap);
1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._domain = map.get(Fields.Domain);
1893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._protocol = map.get(Fields.Protocol);
1903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._application = map.get(Fields.Application);
1913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._name = map.get(Fields.Instance);
1923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._subtype = map.get(Fields.Subtype);
1933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
1943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._port = port;
1953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._weight = weight;
1963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._priority = priority;
1973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._text = text;
1983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.setNeedTextAnnouncing(false);
1993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._state = new ServiceInfoState(this);
2003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._persistent = persistent;
2013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._ipv4Addresses = Collections.synchronizedSet(new LinkedHashSet<Inet4Address>());
2023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._ipv6Addresses = Collections.synchronizedSet(new LinkedHashSet<Inet6Address>());
2033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
2063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * During recovery we need to duplicate service info to reregister them
2073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
2083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param info
2093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
2103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    ServiceInfoImpl(ServiceInfo info) {
2113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._ipv4Addresses = Collections.synchronizedSet(new LinkedHashSet<Inet4Address>());
2123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._ipv6Addresses = Collections.synchronizedSet(new LinkedHashSet<Inet6Address>());
2133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (info != null) {
2143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._domain = info.getDomain();
2153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._protocol = info.getProtocol();
2163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._application = info.getApplication();
2173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._name = info.getName();
2183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._subtype = info.getSubtype();
2193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._port = info.getPort();
2203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._weight = info.getWeight();
2213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._priority = info.getPriority();
2223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._text = info.getTextBytes();
2233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._persistent = info.isPersistent();
2243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Inet6Address[] ipv6Addresses = info.getInet6Addresses();
2253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (Inet6Address address : ipv6Addresses) {
2263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this._ipv6Addresses.add(address);
2273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Inet4Address[] ipv4Addresses = info.getInet4Addresses();
2293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (Inet4Address address : ipv4Addresses) {
2303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this._ipv4Addresses.add(address);
2313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
2333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._state = new ServiceInfoState(this);
2343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static Map<Fields, String> decodeQualifiedNameMap(String type, String name, String subtype) {
2373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<Fields, String> qualifiedNameMap = decodeQualifiedNameMapForType(type);
2383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Instance, name);
2403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Subtype, subtype);
2413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return checkQualifiedNameMap(qualifiedNameMap);
2433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
2443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public static Map<Fields, String> decodeQualifiedNameMapForType(String type) {
2463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        int index;
2473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String casePreservedType = type;
2493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String aType = type.toLowerCase();
2513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String application = aType;
2523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String protocol = "";
2533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String subtype = "";
2543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String name = "";
2553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String domain = "";
2563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (aType.contains("in-addr.arpa") || aType.contains("ip6.arpa")) {
2583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            index = (aType.contains("in-addr.arpa") ? aType.indexOf("in-addr.arpa") : aType.indexOf("ip6.arpa"));
2593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            name = removeSeparators(casePreservedType.substring(0, index));
2603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            domain = casePreservedType.substring(index);
2613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            application = "";
2623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } else if ((!aType.contains("_")) && aType.contains(".")) {
2633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            index = aType.indexOf('.');
2643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            name = removeSeparators(casePreservedType.substring(0, index));
2653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            domain = removeSeparators(casePreservedType.substring(index));
2663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            application = "";
2673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } else {
2683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // First remove the name if it there.
2693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (!aType.startsWith("_") || aType.startsWith("_services")) {
2703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                index = aType.indexOf('.');
2713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (index > 0) {
2723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // We need to preserve the case for the user readable name.
2733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    name = casePreservedType.substring(0, index);
2743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (index + 1 < aType.length()) {
2753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        aType = aType.substring(index + 1);
2763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        casePreservedType = casePreservedType.substring(index + 1);
2773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
2783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
2793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
2813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            index = aType.lastIndexOf("._");
2823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (index > 0) {
2833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int start = index + 2;
2843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int end = aType.indexOf('.', start);
2853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                protocol = casePreservedType.substring(start, end);
2863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (protocol.length() > 0) {
2883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                index = aType.indexOf("_" + protocol.toLowerCase() + ".");
2893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int start = index + protocol.length() + 2;
2903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int end = aType.length() - (aType.endsWith(".") ? 1 : 0);
2913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                domain = casePreservedType.substring(start, end);
2923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                application = casePreservedType.substring(0, index - 1);
2933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
2943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            index = application.toLowerCase().indexOf("._sub");
2953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (index > 0) {
2963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int start = index + 5;
2973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                subtype = removeSeparators(application.substring(0, index));
2983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                application = application.substring(start);
2993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
3003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        final Map<Fields, String> qualifiedNameMap = new HashMap<Fields, String>(5);
3033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Domain, removeSeparators(domain));
3043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Protocol, protocol);
3053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Application, removeSeparators(application));
3063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Instance, name);
3073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        qualifiedNameMap.put(Fields.Subtype, subtype);
3083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return qualifiedNameMap;
3103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    protected static Map<Fields, String> checkQualifiedNameMap(Map<Fields, String> qualifiedNameMap) {
3133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<Fields, String> checkedQualifiedNameMap = new HashMap<Fields, String>(5);
3143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // Optional domain
3163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String domain = (qualifiedNameMap.containsKey(Fields.Domain) ? qualifiedNameMap.get(Fields.Domain) : "local");
3173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((domain == null) || (domain.length() == 0)) {
3183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            domain = "local";
3193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        domain = removeSeparators(domain);
3213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        checkedQualifiedNameMap.put(Fields.Domain, domain);
3223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // Optional protocol
3233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String protocol = (qualifiedNameMap.containsKey(Fields.Protocol) ? qualifiedNameMap.get(Fields.Protocol) : "tcp");
3243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((protocol == null) || (protocol.length() == 0)) {
3253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            protocol = "tcp";
3263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        protocol = removeSeparators(protocol);
3283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        checkedQualifiedNameMap.put(Fields.Protocol, protocol);
3293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // Application
3303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String application = (qualifiedNameMap.containsKey(Fields.Application) ? qualifiedNameMap.get(Fields.Application) : "");
3313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((application == null) || (application.length() == 0)) {
3323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            application = "";
3333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        application = removeSeparators(application);
3353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        checkedQualifiedNameMap.put(Fields.Application, application);
3363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // Instance
3373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String instance = (qualifiedNameMap.containsKey(Fields.Instance) ? qualifiedNameMap.get(Fields.Instance) : "");
3383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((instance == null) || (instance.length() == 0)) {
3393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            instance = "";
3403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // throw new IllegalArgumentException("The instance name component of a fully qualified service cannot be empty.");
3413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        instance = removeSeparators(instance);
3433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        checkedQualifiedNameMap.put(Fields.Instance, instance);
3443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // Optional Subtype
3453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String subtype = (qualifiedNameMap.containsKey(Fields.Subtype) ? qualifiedNameMap.get(Fields.Subtype) : "");
3463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((subtype == null) || (subtype.length() == 0)) {
3473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            subtype = "";
3483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        subtype = removeSeparators(subtype);
3503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        checkedQualifiedNameMap.put(Fields.Subtype, subtype);
3513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return checkedQualifiedNameMap;
3533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static String removeSeparators(String name) {
3563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (name == null) {
3573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return "";
3583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String newName = name.trim();
3603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (newName.startsWith(".")) {
3613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            newName = newName.substring(1);
3623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (newName.startsWith("_")) {
3643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            newName = newName.substring(1);
3653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (newName.endsWith(".")) {
3673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            newName = newName.substring(0, newName.length() - 1);
3683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
3693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return newName;
3703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getType() {
3773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String domain = this.getDomain();
3783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String protocol = this.getProtocol();
3793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String application = this.getApplication();
3803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (application.length() > 0 ? "_" + application + "." : "") + (protocol.length() > 0 ? "_" + protocol + "." : "") + domain + ".";
3813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getTypeWithSubtype() {
3883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String subtype = this.getSubtype();
3893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (subtype.length() > 0 ? "_" + subtype.toLowerCase() + "._sub." : "") + this.getType();
3903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
3923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
3933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
3943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
3953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
3963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getName() {
3973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_name != null ? _name : "");
3983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
3993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getKey() {
4053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this._key == null) {
4063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._key = this.getQualifiedName().toLowerCase();
4073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._key;
4093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Sets the service instance name.
4133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
4143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param name
4153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            unqualified service instance name, such as <code>foobar</code>
4163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void setName(String name) {
4183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._name = name;
4193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._key = null;
4203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getQualifiedName() {
4273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String domain = this.getDomain();
4283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String protocol = this.getProtocol();
4293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String application = this.getApplication();
4303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String instance = this.getName();
4313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // String subtype = this.getSubtype();
4323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // return (instance.length() > 0 ? instance + "." : "") + (application.length() > 0 ? "_" + application + "." : "") + (protocol.length() > 0 ? "_" + protocol + (subtype.length() > 0 ? ",_" + subtype.toLowerCase() + "." : ".") : "") + domain
4333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // + ".";
4343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (instance.length() > 0 ? instance + "." : "") + (application.length() > 0 ? "_" + application + "." : "") + (protocol.length() > 0 ? "_" + protocol + "." : "") + domain + ".";
4353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getServer()
4393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getServer() {
4423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_server != null ? _server : "");
4433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param server
4473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            the server to set
4483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void setServer(String server) {
4503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._server = server;
4513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
4573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getHostAddress() {
4593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String[] names = this.getHostAddresses();
4603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (names.length > 0 ? names[0] : "");
4613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
4673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String[] getHostAddresses() {
4683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Inet4Address[] ip4Aaddresses = this.getInet4Addresses();
4693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Inet6Address[] ip6Aaddresses = this.getInet6Addresses();
4703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String[] names = new String[ip4Aaddresses.length + ip6Aaddresses.length];
4713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (int i = 0; i < ip4Aaddresses.length; i++) {
4723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            names[i] = ip4Aaddresses[i].getHostAddress();
4733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (int i = 0; i < ip6Aaddresses.length; i++) {
4753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            names[i + ip4Aaddresses.length] = "[" + ip6Aaddresses[i].getHostAddress() + "]";
4763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
4773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return names;
4783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param addr
4823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            the addr to add
4833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void addAddress(Inet4Address addr) {
4853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _ipv4Addresses.add(addr);
4863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param addr
4903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            the addr to add
4913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void addAddress(Inet6Address addr) {
4933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _ipv6Addresses.add(addr);
4943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
4953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
4963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
4973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
4983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
4993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
5003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress getAddress() {
5023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getInetAddress();
5033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
5073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
5093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress getInetAddress() {
5113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress[] addresses = this.getInetAddresses();
5123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (addresses.length > 0 ? addresses[0] : null);
5133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
5173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
5193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Inet4Address getInet4Address() {
5213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Inet4Address[] addresses = this.getInet4Addresses();
5223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (addresses.length > 0 ? addresses[0] : null);
5233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
5273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
5293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Inet6Address getInet6Address() {
5313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Inet6Address[] addresses = this.getInet6Addresses();
5323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (addresses.length > 0 ? addresses[0] : null);
5333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
5363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
5373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getInetAddresses()
5383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public InetAddress[] getInetAddresses() {
5413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        List<InetAddress> aList = new ArrayList<InetAddress>(_ipv4Addresses.size() + _ipv6Addresses.size());
5423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        aList.addAll(_ipv4Addresses);
5433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        aList.addAll(_ipv6Addresses);
5443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return aList.toArray(new InetAddress[aList.size()]);
5453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
5483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
5493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getInet4Addresses()
5503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Inet4Address[] getInet4Addresses() {
5533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _ipv4Addresses.toArray(new Inet4Address[_ipv4Addresses.size()]);
5543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
5573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
5583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getInet6Addresses()
5593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Inet6Address[] getInet6Addresses() {
5623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _ipv6Addresses.toArray(new Inet6Address[_ipv6Addresses.size()]);
5633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getPort()
5673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public int getPort() {
5703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _port;
5713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getPriority()
5753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public int getPriority() {
5783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _priority;
5793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getWeight()
5833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public int getWeight() {
5863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _weight;
5873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getTextBytes()
5913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
5923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
5933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public byte[] getTextBytes() {
5943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (this._text != null && this._text.length > 0 ? this._text : DNSRecord.EMPTY_TXT);
5953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
5963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
5973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
5983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
5993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
6013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getTextString() {
6033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<String, byte[]> properties = this.getProperties();
6043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (String key : properties.keySet()) {
6053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            byte[] value = properties.get(key);
6063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((value != null) && (value.length > 0)) {
6073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                return key + "=" + new String(value);
6083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
6093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return key;
6103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return "";
6123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
6153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
6163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getURL()
6173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
6193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getURL() {
6213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getURL("http");
6223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
6253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
6263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getURLs()
6273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String[] getURLs() {
6303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getURLs("http");
6313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
6343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
6353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getURL(java.lang.String)
6363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Deprecated
6383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getURL(String protocol) {
6403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String[] urls = this.getURLs(protocol);
6413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (urls.length > 0 ? urls[0] : protocol + "://null:" + getPort());
6423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
6453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
6463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#getURLs(java.lang.String)
6473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String[] getURLs(String protocol) {
6503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress[] addresses = this.getInetAddresses();
6513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        String[] urls = new String[addresses.length];
6523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (int i = 0; i < addresses.length; i++) {
6533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String url = protocol + "://" + addresses[i].getHostAddress() + ":" + getPort();
6543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            String path = getPropertyString("path");
6553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (path != null) {
6563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (path.indexOf("://") >= 0) {
6573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    url = path;
6583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
6593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    url += path.startsWith("/") ? path : "/" + path;
6603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
6613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
6623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            urls[i] = url;
6633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return urls;
6653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
6683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
6693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public synchronized byte[] getPropertyBytes(String name) {
6723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getProperties().get(name);
6733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
6763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
6773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public synchronized String getPropertyString(String name) {
6803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        byte data[] = this.getProperties().get(name);
6813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (data == null) {
6823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return null;
6833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (data == NO_VALUE) {
6853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            return "true";
6863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
6873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return readUTF(data, 0, data.length);
6883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
6903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
6913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
6923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
6933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
6943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Enumeration<String> getPropertyNames() {
6953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<String, byte[]> properties = this.getProperties();
6963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Collection<String> names = (properties != null ? properties.keySet() : Collections.<String> emptySet());
6973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return new Vector<String>(names).elements();
6983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
6993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
7023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
7043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getApplication() {
7053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_application != null ? _application : "");
7063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
7073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
7103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
7123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getDomain() {
7133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_domain != null ? _domain : "local");
7143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
7153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
7183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
7203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getProtocol() {
7213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_protocol != null ? _protocol : "tcp");
7223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
7233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
7263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
7283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getSubtype() {
7293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_subtype != null ? _subtype : "");
7303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
7313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
7343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
7363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Map<Fields, String> getQualifiedNameMap() {
7373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Map<Fields, String> map = new HashMap<Fields, String>(5);
7383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        map.put(Fields.Domain, this.getDomain());
7403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        map.put(Fields.Protocol, this.getProtocol());
7413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        map.put(Fields.Application, this.getApplication());
7423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        map.put(Fields.Instance, this.getName());
7433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        map.put(Fields.Subtype, this.getSubtype());
7443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return map;
7453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
7463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Write a UTF string with a length to a stream.
7493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    static void writeUTF(OutputStream out, String str) throws IOException {
7513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (int i = 0, len = str.length(); i < len; i++) {
7523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            int c = str.charAt(i);
7533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((c >= 0x0001) && (c <= 0x007F)) {
7543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                out.write(c);
7553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
7563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (c > 0x07FF) {
7573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write(0xE0 | ((c >> 12) & 0x0F));
7583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write(0x80 | ((c >> 6) & 0x3F));
7593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write(0x80 | ((c >> 0) & 0x3F));
7603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                } else {
7613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write(0xC0 | ((c >> 6) & 0x1F));
7623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write(0x80 | ((c >> 0) & 0x3F));
7633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
7643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
7653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
7663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
7673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
7683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
7693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Read data bytes as a UTF stream.
7703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
7713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    String readUTF(byte data[], int off, int len) {
7723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        int offset = off;
7733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        StringBuffer buf = new StringBuffer();
7743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (int end = offset + len; offset < end;) {
7753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            int ch = data[offset++] & 0xFF;
7763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            switch (ch >> 4) {
7773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 0:
7783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 1:
7793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 2:
7803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 3:
7813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 4:
7823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 5:
7833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 6:
7843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 7:
7853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // 0xxxxxxx
7863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
7873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 12:
7883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 13:
7893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (offset >= len) {
7903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        return null;
7913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
7923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // 110x xxxx 10xx xxxx
7933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    ch = ((ch & 0x1F) << 6) | (data[offset++] & 0x3F);
7943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
7953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case 14:
7963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (offset + 2 >= len) {
7973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        return null;
7983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
7993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // 1110 xxxx 10xx xxxx 10xx xxxx
8003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    ch = ((ch & 0x0f) << 12) | ((data[offset++] & 0x3F) << 6) | (data[offset++] & 0x3F);
8013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
8023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                default:
8033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (offset + 1 >= len) {
8043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        return null;
8053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // 10xx xxxx, 1111 xxxx
8073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    ch = ((ch & 0x3F) << 4) | (data[offset++] & 0x0f);
8083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
8093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
8103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            buf.append((char) ch);
8113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return buf.toString();
8133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
8143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    synchronized Map<String, byte[]> getProperties() {
8163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((_props == null) && (this.getTextBytes() != null)) {
8173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Hashtable<String, byte[]> properties = new Hashtable<String, byte[]>();
8183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            try {
8193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                int off = 0;
8203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                while (off < getTextBytes().length) {
8213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // length of the next key value pair
8223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    int len = getTextBytes()[off++] & 0xFF;
8233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if ((len == 0) || (off + len > getTextBytes().length)) {
8243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        properties.clear();
8253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        break;
8263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // look for the '='
8283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    int i = 0;
8293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    for (; (i < len) && (getTextBytes()[off + i] != '='); i++) {
8303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        /* Stub */
8313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    // get the property name
8343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    String name = readUTF(getTextBytes(), off, i);
8353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (name == null) {
8363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        properties.clear();
8373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        break;
8383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (i == len) {
8403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        properties.put(name, NO_VALUE);
8413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    } else {
8423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        byte value[] = new byte[len - ++i];
8433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        System.arraycopy(getTextBytes(), off + i, value, 0, len - i);
8443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        properties.put(name, value);
8453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        off += len;
8463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
8483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } catch (Exception exception) {
8493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                // We should get better logging.
8503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                logger.log(Level.WARNING, "Malformed TXT Field ", exception);
8513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
8523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._props = properties;
8533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
8543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (_props != null ? _props : Collections.<String, byte[]> emptyMap());
8553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
8563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
8573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
8583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * JmDNS callback to update a DNS record.
8593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
8603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param dnsCache
8613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param now
8623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param rec
8633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
8643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
8653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void updateRecord(DNSCache dnsCache, long now, DNSEntry rec) {
8663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if ((rec instanceof DNSRecord) && !rec.isExpired(now)) {
8673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            boolean serviceUpdated = false;
8683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            switch (rec.getRecordType()) {
8693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case TYPE_A: // IPv4
8703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (rec.getName().equalsIgnoreCase(this.getServer())) {
8713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _ipv4Addresses.add((Inet4Address) ((DNSRecord.Address) rec).getAddress());
8723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        serviceUpdated = true;
8733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
8753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case TYPE_AAAA: // IPv6
8763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (rec.getName().equalsIgnoreCase(this.getServer())) {
8773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _ipv6Addresses.add((Inet6Address) ((DNSRecord.Address) rec).getAddress());
8783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        serviceUpdated = true;
8793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
8803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
8813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case TYPE_SRV:
8823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (rec.getName().equalsIgnoreCase(this.getQualifiedName())) {
8833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        DNSRecord.Service srv = (DNSRecord.Service) rec;
8843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        boolean serverChanged = (_server == null) || !_server.equalsIgnoreCase(srv.getServer());
8853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _server = srv.getServer();
8863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _port = srv.getPort();
8873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _weight = srv.getWeight();
8883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _priority = srv.getPriority();
8893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (serverChanged) {
8903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            _ipv4Addresses.clear();
8913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            _ipv6Addresses.clear();
8923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            for (DNSEntry entry : dnsCache.getDNSEntryList(_server, DNSRecordType.TYPE_A, DNSRecordClass.CLASS_IN)) {
8933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                                this.updateRecord(dnsCache, now, entry);
8943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            }
8953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            for (DNSEntry entry : dnsCache.getDNSEntryList(_server, DNSRecordType.TYPE_AAAA, DNSRecordClass.CLASS_IN)) {
8963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                                this.updateRecord(dnsCache, now, entry);
8973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            }
8983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            // We do not want to trigger the listener in this case as it will be triggered if the address resolves.
8993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        } else {
9003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            serviceUpdated = true;
9013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
9023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
9033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
9043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case TYPE_TXT:
9053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (rec.getName().equalsIgnoreCase(this.getQualifiedName())) {
9063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        DNSRecord.Text txt = (DNSRecord.Text) rec;
9073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _text = txt.getText();
9083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _props = null; // set it null for apply update text data
9093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        serviceUpdated = true;
9103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
9113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
9123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                case TYPE_PTR:
9133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if ((this.getSubtype().length() == 0) && (rec.getSubtype().length() != 0)) {
9143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        _subtype = rec.getSubtype();
9153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        serviceUpdated = true;
9163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
9173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
9183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                default:
9193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    break;
9203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
9213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (serviceUpdated && this.hasData()) {
9223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                JmDNSImpl dns = this.getDns();
9233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                if (dns != null) {
9243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    ServiceEvent event = ((DNSRecord) rec).getServiceEvent(dns);
9253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    event = new ServiceEventImpl(dns, event.getType(), event.getName(), this);
9263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    dns.handleServiceResolved(event);
9273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
9283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
9293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // This is done, to notify the wait loop in method JmDNS.waitForInfoData(ServiceInfo info, int timeout);
9303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            synchronized (this) {
9313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                this.notifyAll();
9323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
9333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
9343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * Returns true if the service info is filled with data.
9383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
9393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return <code>true</code> if the service info has data, <code>false</code> otherwise.
9403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public synchronized boolean hasData() {
9433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this.getServer() != null && this.hasInetAddress() && this.getTextBytes() != null && this.getTextBytes().length > 0;
9443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        // return this.getServer() != null && (this.getAddress() != null || (this.getTextBytes() != null && this.getTextBytes().length > 0));
9453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private final boolean hasInetAddress() {
9483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _ipv4Addresses.size() > 0 || _ipv6Addresses.size() > 0;
9493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    // State machine
9523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
9553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean advanceState(DNSTask task) {
9583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.advanceState(task);
9593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
9633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean revertState() {
9663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.revertState();
9673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
9713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean cancelState() {
9743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.cancelState();
9753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
9793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean closeState() {
9823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.closeState();
9833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
9873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean recoverState() {
9903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.recoverState();
9913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
9923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
9933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
9943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
9953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
9963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
9973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void removeAssociationWithTask(DNSTask task) {
9983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _state.removeAssociationWithTask(task);
9993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void associateWithTask(DNSTask task, DNSState state) {
10063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        _state.associateWithTask(task, state);
10073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isAssociatedWithTask(DNSTask task, DNSState state) {
10143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isAssociatedWithTask(task, state);
10153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isProbing() {
10223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isProbing();
10233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isAnnouncing() {
10303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isAnnouncing();
10313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isAnnounced() {
10383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isAnnounced();
10393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isCanceling() {
10463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.isCanceling();
10473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isCanceled() {
10543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isCanceled();
10553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isClosing() {
10623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isClosing();
10633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isClosed() {
10703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.isClosed();
10713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean waitForAnnounced(long timeout) {
10783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.waitForAnnounced(timeout);
10793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean waitForCanceled(long timeout) {
10863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _state.waitForCanceled(timeout);
10873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
10923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
10933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public int hashCode() {
10943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return getQualifiedName().hashCode();
10953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
10963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
10973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
10983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
10993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
11003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
11013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean equals(Object obj) {
11023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (obj instanceof ServiceInfoImpl) && getQualifiedName().equals(((ServiceInfoImpl) obj).getQualifiedName());
11033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
11043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
11053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
11063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
11073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
11083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
11093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String getNiceTextString() {
11103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        StringBuffer buf = new StringBuffer();
11113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (int i = 0, len = this.getTextBytes().length; i < len; i++) {
11123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (i >= 200) {
11133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append("...");
11143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                break;
11153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
11163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            int ch = getTextBytes()[i] & 0xFF;
11173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if ((ch < ' ') || (ch > 127)) {
11183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append("\\0");
11193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append(Integer.toString(ch, 8));
11203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
11213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append((char) ch);
11223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
11233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
11243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return buf.toString();
11253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
11263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
11273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /*
11283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * (non-Javadoc)
11293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @see javax.jmdns.ServiceInfo#clone()
11303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
11313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
11323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public ServiceInfoImpl clone() {
11333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        ServiceInfoImpl serviceInfo = new ServiceInfoImpl(this.getQualifiedNameMap(), _port, _weight, _priority, _persistent, _text);
11343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Inet6Address[] ipv6Addresses = this.getInet6Addresses();
11353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (Inet6Address address : ipv6Addresses) {
11363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            serviceInfo._ipv6Addresses.add(address);
11373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
11383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        Inet4Address[] ipv4Addresses = this.getInet4Addresses();
11393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        for (Inet4Address address : ipv4Addresses) {
11403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            serviceInfo._ipv4Addresses.add(address);
11413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
11423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return serviceInfo;
11433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
11443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
11453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
11463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
11473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
11483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
11493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public String toString() {
11503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        StringBuilder buf = new StringBuilder();
11513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("[" + this.getClass().getSimpleName() + "@" + System.identityHashCode(this) + " ");
11523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("name: '");
11533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append((this.getName().length() > 0 ? this.getName() + "." : "") + this.getTypeWithSubtype());
11543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("' address: '");
11553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        InetAddress[] addresses = this.getInetAddresses();
11563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (addresses.length > 0) {
11573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            for (InetAddress address : addresses) {
11583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append(address);
11593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append(':');
11603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append(this.getPort());
11613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append(' ');
11623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
11633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        } else {
11643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            buf.append("(null):");
11653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            buf.append(this.getPort());
11663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
11673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("' status: '");
11683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(_state.toString());
11693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(this.isPersistent() ? "' is persistent," : "',");
11703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(" has ");
11713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(this.hasData() ? "" : "NO ");
11723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append("data");
11733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getTextBytes().length > 0) {
11743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // buf.append("\n");
11753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            // buf.append(this.getNiceTextString());
11763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            Map<String, byte[]> properties = this.getProperties();
11773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            if (!properties.isEmpty()) {
11783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append("\n");
11793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                for (String key : properties.keySet()) {
11803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    buf.append("\t" + key + ": " + new String(properties.get(key)) + "\n");
11813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
11823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } else {
11833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                buf.append(" empty");
11843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
11853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
11863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        buf.append(']');
11873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return buf.toString();
11883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
11893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
11903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public Collection<DNSRecord> answers(boolean unique, int ttl, HostInfo localHost) {
11913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        List<DNSRecord> list = new ArrayList<DNSRecord>();
11923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this.getSubtype().length() > 0) {
11933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            list.add(new Pointer(this.getTypeWithSubtype(), DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE, ttl, this.getQualifiedName()));
11943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
11953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        list.add(new Pointer(this.getType(), DNSRecordClass.CLASS_IN, DNSRecordClass.NOT_UNIQUE, ttl, this.getQualifiedName()));
11963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        list.add(new Service(this.getQualifiedName(), DNSRecordClass.CLASS_IN, unique, ttl, _priority, _weight, _port, localHost.getName()));
11973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        list.add(new Text(this.getQualifiedName(), DNSRecordClass.CLASS_IN, unique, ttl, this.getTextBytes()));
11983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return list;
11993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
12023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
12033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
12043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
12053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void setText(byte[] text) throws IllegalStateException {
12063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        synchronized (this) {
12073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._text = text;
12083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this._props = null;
12093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            this.setNeedTextAnnouncing(true);
12103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
12113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
12143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
12153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
12163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
12173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void setText(Map<String, ?> props) throws IllegalStateException {
12183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this.setText(textFromProperties(props));
12193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
12223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * This is used internally by the framework
12233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *
12243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param text
12253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
12263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void _setText(byte[] text) {
12273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._text = text;
12283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._props = null;
12293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    private static byte[] textFromProperties(Map<String, ?> props) {
12323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        byte[] text = null;
12333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (props != null) {
12343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            try {
12353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                ByteArrayOutputStream out = new ByteArrayOutputStream(256);
12363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                for (String key : props.keySet()) {
12373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    Object val = props.get(key);
12383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    ByteArrayOutputStream out2 = new ByteArrayOutputStream(100);
12393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    writeUTF(out2, key);
12403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (val == null) {
12413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        // Skip
12423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    } else if (val instanceof String) {
12433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        out2.write('=');
12443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        writeUTF(out2, (String) val);
12453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    } else if (val instanceof byte[]) {
12463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        byte[] bval = (byte[]) val;
12473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        if (bval.length > 0) {
12483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            out2.write('=');
12493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            out2.write(bval, 0, bval.length);
12503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        } else {
12513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                            val = null;
12523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        }
12533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    } else {
12543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        throw new IllegalArgumentException("invalid property value: " + val);
12553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
12563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    byte data[] = out2.toByteArray();
12573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    if (data.length > 255) {
12583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                        throw new IOException("Cannot have individual values larger that 255 chars. Offending value: " + key + (val != null ? "" : "=" + val));
12593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    }
12603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write((byte) data.length);
12613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                    out.write(data, 0, data.length);
12623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                }
12633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                text = out.toByteArray();
12643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            } catch (IOException e) {
12653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman                throw new RuntimeException("unexpected exception: " + e);
12663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            }
12673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
12683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return (text != null && text.length > 0 ? text : DNSRecord.EMPTY_TXT);
12693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void setDns(JmDNSImpl dns) {
12723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._state.setDns(dns);
12733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
12763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
12773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
12783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
12793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public JmDNSImpl getDns() {
12803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._state.getDns();
12813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
12843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * {@inheritDoc}
12853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
12863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    @Override
12873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean isPersistent() {
12883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _persistent;
12893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
12903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
12913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
12923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param needTextAnnouncing
12933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            the needTextAnnouncing to set
12943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
12953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public void setNeedTextAnnouncing(boolean needTextAnnouncing) {
12963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._needTextAnnouncing = needTextAnnouncing;
12973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        if (this._needTextAnnouncing) {
12983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman            _state.setTask(null);
12993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        }
13003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
13013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
13023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
13033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return the needTextAnnouncing
13043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
13053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    public boolean needTextAnnouncing() {
13063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return _needTextAnnouncing;
13073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
13083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
13093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
13103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @return the delegate
13113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
13123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    Delegate getDelegate() {
13133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        return this._delegate;
13143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
13153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
13163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    /**
13173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     * @param delegate
13183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     *            the delegate to set
13193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman     */
13203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    void setDelegate(Delegate delegate) {
13213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman        this._delegate = delegate;
13223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman    }
13233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman
13243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman}
1325