13742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman// Licensed under Apache License version 2.0 23742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpackage javax.jmdns.impl.tasks.state; 33742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 43742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.io.IOException; 53742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.ArrayList; 63742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.List; 73742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Level; 83742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport java.util.logging.Logger; 93742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.ServiceInfo; 113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSOutgoing; 123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.DNSStatefulObject; 133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.JmDNSImpl; 143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.ServiceInfoImpl; 153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSConstants; 163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.constants.DNSState; 173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanimport javax.jmdns.impl.tasks.DNSTask; 183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman/** 203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * This is the root class for all state tasks. These tasks work with objects that implements the {@link javax.jmdns.impl.DNSStatefulObject} interface and therefore participate in the state machine. 213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @author Pierre Frisch 233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Romanpublic abstract class DNSStateTask extends DNSTask { 253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman static Logger logger1 = Logger.getLogger(DNSStateTask.class.getName()); 263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * By setting a 0 ttl we effectively expire the record. 293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private final int _ttl; 313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private static int _defaultTTL = DNSConstants.DNS_TTL; 333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * The state of the task. 363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman private DNSState _taskState = null; 383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public abstract String getTaskDescription(); 403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static int defaultTTL() { 423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _defaultTTL; 433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * For testing only do not use in production. 473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param value 493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public static void setDefaultTTL(int value) { 513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _defaultTTL = value; 523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param jmDNSImpl 563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param ttl 573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public DNSStateTask(JmDNSImpl jmDNSImpl, int ttl) { 593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman super(jmDNSImpl); 603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman _ttl = ttl; 613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return the ttl 653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public int getTTL() { 673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return _ttl; 683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Associate the DNS host and the service infos with this task if not already associated and in the same state. 723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * 733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param state 743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * target state 753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected void associate(DNSState state) { 773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this.getDns()) { 783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getDns().associateWithTask(this, state); 793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceInfo serviceInfo : this.getDns().getServices().values()) { 813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ((ServiceInfoImpl) serviceInfo).associateWithTask(this, state); 823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * Remove the DNS host and service info association with this task. 873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected void removeAssociation() { 893742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Remove association from host to this 903742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this.getDns()) { 913742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getDns().removeAssociationWithTask(this); 923742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 933742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 943742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Remove associations from services to this 953742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceInfo serviceInfo : this.getDns().getServices().values()) { 963742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ((ServiceInfoImpl) serviceInfo).removeAssociationWithTask(this); 973742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 983742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 993742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1003742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman @Override 1013742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman public void run() { 1023742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman DNSOutgoing out = this.createOugoing(); 1033742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman try { 1043742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!this.checkRunCondition()) { 1053742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.cancel(); 1063742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 1073742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1083742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman List<DNSStatefulObject> stateObjects = new ArrayList<DNSStatefulObject>(); 1093742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // send probes for JmDNS itself 1103742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (this.getDns()) { 1113742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (this.getDns().isAssociatedWithTask(this, this.getTaskState())) { 1123742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger1.finer(this.getName() + ".run() JmDNS " + this.getTaskDescription() + " " + this.getDns().getName()); 1133742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman stateObjects.add(this.getDns()); 1143742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman out = this.buildOutgoingForDNS(out); 1153742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1163742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1173742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // send probes for services 1183742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (ServiceInfo serviceInfo : this.getDns().getServices().values()) { 1193742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo; 1203742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1213742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (info) { 1223742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (info.isAssociatedWithTask(this, this.getTaskState())) { 1233742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger1.fine(this.getName() + ".run() JmDNS " + this.getTaskDescription() + " " + info.getQualifiedName()); 1243742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman stateObjects.add(info); 1253742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman out = this.buildOutgoingForInfo(info, out); 1263742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1273742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1283742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1293742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (!out.isEmpty()) { 1303742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger1.finer(this.getName() + ".run() JmDNS " + this.getTaskDescription() + " #" + this.getTaskState()); 1313742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.getDns().send(out); 1323742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1333742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Advance the state of objects. 1343742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.advanceObjectsState(stateObjects); 1353742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } else { 1363742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // Advance the state of objects. 1373742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.advanceObjectsState(stateObjects); 1383742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1393742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman // If we have nothing to send, another timer taskState ahead of us has done the job for us. We can cancel. 1403742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman cancel(); 1413742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return; 1423742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1433742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } catch (Throwable e) { 1443742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman logger1.log(Level.WARNING, this.getName() + ".run() exception ", e); 1453742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.recoverTask(e); 1463742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1473742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1483742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this.advanceTask(); 1493742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1503742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1513742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected abstract boolean checkRunCondition(); 1523742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1533742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected abstract DNSOutgoing buildOutgoingForDNS(DNSOutgoing out) throws IOException; 1543742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1553742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected abstract DNSOutgoing buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out) throws IOException; 1563742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1573742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected abstract DNSOutgoing createOugoing(); 1583742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1593742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected void advanceObjectsState(List<DNSStatefulObject> list) { 1603742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman if (list != null) { 1613742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman for (DNSStatefulObject object : list) { 1623742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman synchronized (object) { 1633742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman object.advanceState(this); 1643742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1653742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1663742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1673742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1683742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1693742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected abstract void recoverTask(Throwable e); 1703742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1713742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected abstract void advanceTask(); 1723742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1733742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1743742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @return the taskState 1753742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1763742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected DNSState getTaskState() { 1773742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman return this._taskState; 1783742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1793742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1803742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman /** 1813742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * @param taskState 1823742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman * the taskState to set 1833742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman */ 1843742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman protected void setTaskState(DNSState taskState) { 1853742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman this._taskState = taskState; 1863742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman } 1873742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman 1883742d9db8b6edb10627b0f89336cca5249f1d15aManuel Roman} 189