Home | History | Annotate | Download | only in state
      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 }
    189