Go to the documentation of this file.00001
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
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 }