• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Licensed under Apache License version 2.0
2 package javax.jmdns.impl.tasks.state;
3 
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.List;
7 import java.util.logging.Level;
8 import java.util.logging.Logger;
9 
10 import javax.jmdns.ServiceInfo;
11 import javax.jmdns.impl.DNSOutgoing;
12 import javax.jmdns.impl.DNSStatefulObject;
13 import javax.jmdns.impl.JmDNSImpl;
14 import javax.jmdns.impl.ServiceInfoImpl;
15 import javax.jmdns.impl.constants.DNSConstants;
16 import javax.jmdns.impl.constants.DNSState;
17 import javax.jmdns.impl.tasks.DNSTask;
18 
19 /**
20  * 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.
21  *
22  * @author Pierre Frisch
23  */
24 public abstract class DNSStateTask extends DNSTask {
25     static Logger      logger1     = Logger.getLogger(DNSStateTask.class.getName());
26 
27     /**
28      * By setting a 0 ttl we effectively expire the record.
29      */
30     private final int  _ttl;
31 
32     private static int _defaultTTL = DNSConstants.DNS_TTL;
33 
34     /**
35      * The state of the task.
36      */
37     private DNSState   _taskState  = null;
38 
getTaskDescription()39     public abstract String getTaskDescription();
40 
defaultTTL()41     public static int defaultTTL() {
42         return _defaultTTL;
43     }
44 
45     /**
46      * For testing only do not use in production.
47      *
48      * @param value
49      */
setDefaultTTL(int value)50     public static void setDefaultTTL(int value) {
51         _defaultTTL = value;
52     }
53 
54     /**
55      * @param jmDNSImpl
56      * @param ttl
57      */
DNSStateTask(JmDNSImpl jmDNSImpl, int ttl)58     public DNSStateTask(JmDNSImpl jmDNSImpl, int ttl) {
59         super(jmDNSImpl);
60         _ttl = ttl;
61     }
62 
63     /**
64      * @return the ttl
65      */
getTTL()66     public int getTTL() {
67         return _ttl;
68     }
69 
70     /**
71      * Associate the DNS host and the service infos with this task if not already associated and in the same state.
72      *
73      * @param state
74      *            target state
75      */
associate(DNSState state)76     protected void associate(DNSState state) {
77         synchronized (this.getDns()) {
78             this.getDns().associateWithTask(this, state);
79         }
80         for (ServiceInfo serviceInfo : this.getDns().getServices().values()) {
81             ((ServiceInfoImpl) serviceInfo).associateWithTask(this, state);
82         }
83     }
84 
85     /**
86      * Remove the DNS host and service info association with this task.
87      */
removeAssociation()88     protected void removeAssociation() {
89         // Remove association from host to this
90         synchronized (this.getDns()) {
91             this.getDns().removeAssociationWithTask(this);
92         }
93 
94         // Remove associations from services to this
95         for (ServiceInfo serviceInfo : this.getDns().getServices().values()) {
96             ((ServiceInfoImpl) serviceInfo).removeAssociationWithTask(this);
97         }
98     }
99 
100     @Override
run()101     public void run() {
102         DNSOutgoing out = this.createOugoing();
103         try {
104             if (!this.checkRunCondition()) {
105                 this.cancel();
106                 return;
107             }
108             List<DNSStatefulObject> stateObjects = new ArrayList<DNSStatefulObject>();
109             // send probes for JmDNS itself
110             synchronized (this.getDns()) {
111                 if (this.getDns().isAssociatedWithTask(this, this.getTaskState())) {
112                     logger1.finer(this.getName() + ".run() JmDNS " + this.getTaskDescription() + " " + this.getDns().getName());
113                     stateObjects.add(this.getDns());
114                     out = this.buildOutgoingForDNS(out);
115                 }
116             }
117             // send probes for services
118             for (ServiceInfo serviceInfo : this.getDns().getServices().values()) {
119                 ServiceInfoImpl info = (ServiceInfoImpl) serviceInfo;
120 
121                 synchronized (info) {
122                     if (info.isAssociatedWithTask(this, this.getTaskState())) {
123                         logger1.fine(this.getName() + ".run() JmDNS " + this.getTaskDescription() + " " + info.getQualifiedName());
124                         stateObjects.add(info);
125                         out = this.buildOutgoingForInfo(info, out);
126                     }
127                 }
128             }
129             if (!out.isEmpty()) {
130                 logger1.finer(this.getName() + ".run() JmDNS " + this.getTaskDescription() + " #" + this.getTaskState());
131                 this.getDns().send(out);
132 
133                 // Advance the state of objects.
134                 this.advanceObjectsState(stateObjects);
135             } else {
136                 // Advance the state of objects.
137                 this.advanceObjectsState(stateObjects);
138 
139                 // If we have nothing to send, another timer taskState ahead of us has done the job for us. We can cancel.
140                 cancel();
141                 return;
142             }
143         } catch (Throwable e) {
144             logger1.log(Level.WARNING, this.getName() + ".run() exception ", e);
145             this.recoverTask(e);
146         }
147 
148         this.advanceTask();
149     }
150 
checkRunCondition()151     protected abstract boolean checkRunCondition();
152 
buildOutgoingForDNS(DNSOutgoing out)153     protected abstract DNSOutgoing buildOutgoingForDNS(DNSOutgoing out) throws IOException;
154 
buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out)155     protected abstract DNSOutgoing buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out) throws IOException;
156 
createOugoing()157     protected abstract DNSOutgoing createOugoing();
158 
advanceObjectsState(List<DNSStatefulObject> list)159     protected void advanceObjectsState(List<DNSStatefulObject> list) {
160         if (list != null) {
161             for (DNSStatefulObject object : list) {
162                 synchronized (object) {
163                     object.advanceState(this);
164                 }
165             }
166         }
167     }
168 
recoverTask(Throwable e)169     protected abstract void recoverTask(Throwable e);
170 
advanceTask()171     protected abstract void advanceTask();
172 
173     /**
174      * @return the taskState
175      */
getTaskState()176     protected DNSState getTaskState() {
177         return this._taskState;
178     }
179 
180     /**
181      * @param taskState
182      *            the taskState to set
183      */
setTaskState(DNSState taskState)184     protected void setTaskState(DNSState taskState) {
185         this._taskState = taskState;
186     }
187 
188 }
189