com.alibaba.nacos.common.utils.Observable Maven / Gradle / Ivy
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.common.utils;
import java.util.Objects;
import java.util.Set;
/**
* Observable utils.
*
* @author liaochuntao
*/
public class Observable {
private transient boolean changed = false;
private transient Set obs = new ConcurrentHashSet<>();
private volatile int observerCnt = 0;
/**
* Adds an observer to the set of observers for this object, provided that it is not the same as some observer
* already in the set. The order in which notifications will be delivered to multiple observers is not specified.
* See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
Objects.requireNonNull(o, "Observer");
obs.add(o);
observerCnt++;
o.update(this);
}
/**
* Deletes an observer from the set of observers of this object. Passing {@code null} to this method will have no
* effect.
*
* @param o the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.remove(o);
observerCnt--;
}
/**
* If this object has changed, as indicated by the {@code hasChanged} method, then notify all of its observers and
* then call the {@code clearChanged} method to indicate that this object has no longer changed.
*
* Each observer has its {@code update} method called with one argument: this observable object.
*/
public void notifyObservers() {
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
if (!changed) {
return;
}
clearChanged();
}
for (Observer observer : obs) {
observer.update(this);
}
}
/**
* Clears the observer list so that this object no longer has any observers.
*/
public void deleteObservers() {
obs.clear();
}
/**
* Marks this {@code Observable} object as having been changed; the {@code hasChanged} method will now return {@code
* true}.
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* Indicates that this object has no longer changed, or that it has already notified all of its observers of its
* most recent change, so that the {@code hasChanged} method will now return {@code false}. This method is called
* automatically by the {@code notifyObservers} methods.
*
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
*/
protected synchronized void clearChanged() {
changed = false;
}
/**
* Tests if this object has changed.
*
* @return {@code true} if and only if the {@code setChanged} method has been called more recently than the {@code
* clearChanged} method on this object; {@code false} otherwise.
*/
public synchronized boolean hasChanged() {
return changed;
}
/**
* Returns the number of observers of this {@code Observable} object.
*
* @return the number of observers of this object.
*/
public int countObservers() {
return observerCnt;
}
}