View Javadoc

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  
39      public abstract String getTaskDescription();
40  
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       */
50      public static void setDefaultTTL(int value) {
51          _defaultTTL = value;
52      }
53  
54      /**
55       * @param jmDNSImpl
56       * @param ttl
57       */
58      public DNSStateTask(JmDNSImpl jmDNSImpl, int ttl) {
59          super(jmDNSImpl);
60          _ttl = ttl;
61      }
62  
63      /**
64       * @return the ttl
65       */
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       */
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       */
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
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 
151     protected abstract boolean checkRunCondition();
152 
153     protected abstract DNSOutgoing buildOutgoingForDNS(DNSOutgoing out) throws IOException;
154 
155     protected abstract DNSOutgoing buildOutgoingForInfo(ServiceInfoImpl info, DNSOutgoing out) throws IOException;
156 
157     protected abstract DNSOutgoing createOugoing();
158 
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 
169     protected abstract void recoverTask(Throwable e);
170 
171     protected abstract void advanceTask();
172 
173     /**
174      * @return the taskState
175      */
176     protected DNSState getTaskState() {
177         return this._taskState;
178     }
179 
180     /**
181      * @param taskState
182      *            the taskState to set
183      */
184     protected void setTaskState(DNSState taskState) {
185         this._taskState = taskState;
186     }
187 
188 }