$search
00001 // Licensed under Apache License version 2.0 00002 package javax.jmdns.impl; 00003 00004 import java.util.Collection; 00005 import java.util.concurrent.ConcurrentHashMap; 00006 import java.util.concurrent.ConcurrentMap; 00007 import java.util.concurrent.Semaphore; 00008 import java.util.concurrent.TimeUnit; 00009 import java.util.concurrent.locks.ReentrantLock; 00010 import java.util.logging.Level; 00011 import java.util.logging.Logger; 00012 00013 import javax.jmdns.impl.constants.DNSState; 00014 import javax.jmdns.impl.tasks.DNSTask; 00015 00022 public interface DNSStatefulObject { 00023 00032 public static final class DNSStatefulObjectSemaphore { 00033 private static Logger logger = Logger.getLogger(DNSStatefulObjectSemaphore.class.getName()); 00034 00035 private final String _name; 00036 00037 private final ConcurrentMap<Thread, Semaphore> _semaphores; 00038 00043 public DNSStatefulObjectSemaphore(String name) { 00044 super(); 00045 _name = name; 00046 _semaphores = new ConcurrentHashMap<Thread, Semaphore>(50); 00047 } 00048 00055 public void waitForEvent(long timeout) { 00056 Thread thread = Thread.currentThread(); 00057 Semaphore semaphore = _semaphores.get(thread); 00058 if (semaphore == null) { 00059 semaphore = new Semaphore(1, true); 00060 semaphore.drainPermits(); 00061 _semaphores.putIfAbsent(thread, semaphore); 00062 } 00063 semaphore = _semaphores.get(thread); 00064 try { 00065 semaphore.tryAcquire(timeout, TimeUnit.MILLISECONDS); 00066 } catch (InterruptedException exception) { 00067 logger.log(Level.FINER, "Exception ", exception); 00068 } 00069 } 00070 00074 public void signalEvent() { 00075 Collection<Semaphore> semaphores = _semaphores.values(); 00076 for (Semaphore semaphore : semaphores) { 00077 semaphore.release(); 00078 semaphores.remove(semaphore); 00079 } 00080 } 00081 00082 @Override 00083 public String toString() { 00084 StringBuilder aLog = new StringBuilder(1000); 00085 aLog.append("Semaphore: "); 00086 aLog.append(this._name); 00087 if (_semaphores.size() == 0) { 00088 aLog.append(" no semaphores."); 00089 } else { 00090 aLog.append(" semaphores:\n"); 00091 for (Thread thread : _semaphores.keySet()) { 00092 aLog.append("\tThread: "); 00093 aLog.append(thread.getName()); 00094 aLog.append(' '); 00095 aLog.append(_semaphores.get(thread)); 00096 aLog.append('\n'); 00097 } 00098 } 00099 return aLog.toString(); 00100 } 00101 00102 } 00103 00104 public static class DefaultImplementation extends ReentrantLock implements DNSStatefulObject { 00105 private static Logger logger = Logger.getLogger(DefaultImplementation.class.getName()); 00106 00107 private static final long serialVersionUID = -3264781576883412227L; 00108 00109 private volatile JmDNSImpl _dns; 00110 00111 protected volatile DNSTask _task; 00112 00113 protected volatile DNSState _state; 00114 00115 private final DNSStatefulObjectSemaphore _announcing; 00116 00117 private final DNSStatefulObjectSemaphore _canceling; 00118 00119 public DefaultImplementation() { 00120 super(); 00121 _dns = null; 00122 _task = null; 00123 _state = DNSState.PROBING_1; 00124 _announcing = new DNSStatefulObjectSemaphore("Announce"); 00125 _canceling = new DNSStatefulObjectSemaphore("Cancel"); 00126 } 00127 00131 @Override 00132 public JmDNSImpl getDns() { 00133 return this._dns; 00134 } 00135 00136 protected void setDns(JmDNSImpl dns) { 00137 this._dns = dns; 00138 } 00139 00143 @Override 00144 public void associateWithTask(DNSTask task, DNSState state) { 00145 if (this._task == null && this._state == state) { 00146 this.lock(); 00147 try { 00148 if (this._task == null && this._state == state) { 00149 this.setTask(task); 00150 } 00151 } finally { 00152 this.unlock(); 00153 } 00154 } 00155 } 00156 00160 @Override 00161 public void removeAssociationWithTask(DNSTask task) { 00162 if (this._task == task) { 00163 this.lock(); 00164 try { 00165 if (this._task == task) { 00166 this.setTask(null); 00167 } 00168 } finally { 00169 this.unlock(); 00170 } 00171 } 00172 } 00173 00177 @Override 00178 public boolean isAssociatedWithTask(DNSTask task, DNSState state) { 00179 this.lock(); 00180 try { 00181 return this._task == task && this._state == state; 00182 } finally { 00183 this.unlock(); 00184 } 00185 } 00186 00187 protected void setTask(DNSTask task) { 00188 this._task = task; 00189 } 00190 00195 protected void setState(DNSState state) { 00196 this.lock(); 00197 try { 00198 this._state = state; 00199 if (this.isAnnounced()) { 00200 _announcing.signalEvent(); 00201 } 00202 if (this.isCanceled()) { 00203 _canceling.signalEvent(); 00204 // clear any waiting announcing 00205 _announcing.signalEvent(); 00206 } 00207 } finally { 00208 this.unlock(); 00209 } 00210 } 00211 00215 @Override 00216 public boolean advanceState(DNSTask task) { 00217 boolean result = true; 00218 if (this._task == task) { 00219 this.lock(); 00220 try { 00221 if (this._task == task) { 00222 this.setState(this._state.advance()); 00223 } else { 00224 logger.warning("Trying to advance state whhen not the owner. owner: " + this._task + " perpetrator: " + task); 00225 } 00226 } finally { 00227 this.unlock(); 00228 } 00229 } 00230 return result; 00231 } 00232 00236 @Override 00237 public boolean revertState() { 00238 boolean result = true; 00239 if (!this.willCancel()) { 00240 this.lock(); 00241 try { 00242 if (!this.willCancel()) { 00243 this.setState(this._state.revert()); 00244 this.setTask(null); 00245 } 00246 } finally { 00247 this.unlock(); 00248 } 00249 } 00250 return result; 00251 } 00252 00256 @Override 00257 public boolean cancelState() { 00258 boolean result = false; 00259 if (!this.willCancel()) { 00260 this.lock(); 00261 try { 00262 if (!this.willCancel()) { 00263 this.setState(DNSState.CANCELING_1); 00264 this.setTask(null); 00265 result = true; 00266 } 00267 } finally { 00268 this.unlock(); 00269 } 00270 } 00271 return result; 00272 } 00273 00277 @Override 00278 public boolean closeState() { 00279 boolean result = false; 00280 if (!this.willClose()) { 00281 this.lock(); 00282 try { 00283 if (!this.willClose()) { 00284 this.setState(DNSState.CLOSING); 00285 this.setTask(null); 00286 result = true; 00287 } 00288 } finally { 00289 this.unlock(); 00290 } 00291 } 00292 return result; 00293 } 00294 00298 @Override 00299 public boolean recoverState() { 00300 boolean result = false; 00301 this.lock(); 00302 try { 00303 this.setState(DNSState.PROBING_1); 00304 this.setTask(null); 00305 } finally { 00306 this.unlock(); 00307 } 00308 return result; 00309 } 00310 00314 @Override 00315 public boolean isProbing() { 00316 return this._state.isProbing(); 00317 } 00318 00322 @Override 00323 public boolean isAnnouncing() { 00324 return this._state.isAnnouncing(); 00325 } 00326 00330 @Override 00331 public boolean isAnnounced() { 00332 return this._state.isAnnounced(); 00333 } 00334 00338 @Override 00339 public boolean isCanceling() { 00340 return this._state.isCanceling(); 00341 } 00342 00346 @Override 00347 public boolean isCanceled() { 00348 return this._state.isCanceled(); 00349 } 00350 00354 @Override 00355 public boolean isClosing() { 00356 return this._state.isClosing(); 00357 } 00358 00362 @Override 00363 public boolean isClosed() { 00364 return this._state.isClosed(); 00365 } 00366 00367 private boolean willCancel() { 00368 return this._state.isCanceled() || this._state.isCanceling(); 00369 } 00370 00371 private boolean willClose() { 00372 return this._state.isClosed() || this._state.isClosing(); 00373 } 00374 00378 @Override 00379 public boolean waitForAnnounced(long timeout) { 00380 if (!this.isAnnounced() && !this.willCancel()) { 00381 _announcing.waitForEvent(timeout); 00382 } 00383 if (!this.isAnnounced()) { 00384 if (this.willCancel() || this.willClose()) { 00385 logger.fine("Wait for announced cancelled: " + this); 00386 } else { 00387 logger.warning("Wait for announced timed out: " + this); 00388 } 00389 } 00390 return this.isAnnounced(); 00391 } 00392 00396 @Override 00397 public boolean waitForCanceled(long timeout) { 00398 if (!this.isCanceled()) { 00399 _canceling.waitForEvent(timeout); 00400 } 00401 if (!this.isCanceled() && !this.willClose()) { 00402 logger.warning("Wait for canceled timed out: " + this); 00403 } 00404 return this.isCanceled(); 00405 } 00406 00410 @Override 00411 public String toString() { 00412 return (_dns != null ? "DNS: " + _dns.getName() : "NO DNS") + " state: " + _state + " task: " + _task; 00413 } 00414 00415 } 00416 00422 public JmDNSImpl getDns(); 00423 00432 public void associateWithTask(DNSTask task, DNSState state); 00433 00440 public void removeAssociationWithTask(DNSTask task); 00441 00451 public boolean isAssociatedWithTask(DNSTask task, DNSState state); 00452 00461 public boolean advanceState(DNSTask task); 00462 00469 public boolean revertState(); 00470 00476 public boolean cancelState(); 00477 00483 public boolean closeState(); 00484 00490 public boolean recoverState(); 00491 00497 public boolean isProbing(); 00498 00504 public boolean isAnnouncing(); 00505 00511 public boolean isAnnounced(); 00512 00518 public boolean isCanceling(); 00519 00525 public boolean isCanceled(); 00526 00532 public boolean isClosing(); 00533 00539 public boolean isClosed(); 00540 00548 public boolean waitForAnnounced(long timeout); 00549 00557 public boolean waitForCanceled(long timeout); 00558 00559 }