net.sf.eBusx.monitor.Monitor Maven / Gradle / Ivy
//
// Copyright 2011, 2012, 2015, 2016, 2019 Charles W. Rapp
//
// 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 net.sf.eBusx.monitor;
import com.google.common.base.Strings;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sf.eBus.client.EFeed;
import net.sf.eBus.client.EFeed.FeedScope;
import net.sf.eBus.client.EFeedState;
import net.sf.eBus.client.EPublishFeed;
import net.sf.eBus.client.EPublisher;
import net.sf.eBus.client.EReplier;
import net.sf.eBus.client.EReplyFeed;
import net.sf.eBus.client.EReplyFeed.ERequest;
import net.sf.eBus.client.IEPublishFeed;
import net.sf.eBus.messages.EField;
import net.sf.eBus.messages.EMessageKey;
import net.sf.eBus.messages.EReplyMessage.ReplyStatus;
import net.sf.eBus.messages.type.DataType;
import net.sf.eBus.util.IndexPool;
/**
* This class provides static methods, interfacing with the eBus
* monitoring subsystem. {@link Monitorable} objects must
* {@link #register(net.sf.eBusx.monitor.Monitorable) register}
* prior to calling
* {@link #update(ActionLevel, String, String, Monitorable) updating}
* its current state or reporting
* {@link #transientStatus(ActionLevel, String, String, Monitorable) transient events}.
* When monitorable objects
* {@link #deregister(Monitorable) deregisters}, the monitor
* status is retracted.
*
* This class publishes the optional
* {@link #applicationInfo(String, String, String, String, EField) application information}.
* This information is generally set once upon application
* start and not changed although that is allowed. This class
* also publishes the
* {@link MonitorUpdate} notification which reports to
* subscribers newly registered or de-registered monitorable
* objects.
* Finally, this class sends
* {@link MonitoredObjectReply} replies to
* {@link MonitoredObjectRequest} messages. These replies contain
* the list of currently register monitorable objects.
*
* @author Charles Rapp
*/
public final class Monitor
{
//---------------------------------------------------------------
// Member data.
//
//-----------------------------------------------------------
// Constants.
//
/**
* {@link #MONITOR_UPDATE_SUBJECT} is advertised with the
* subject "net.sf.eBusx.monitor" to form this notification
* key.
*/
public static final String MONITOR_UPDATE_SUBJECT =
"net.sf.eBusx.monitor";
/**
* {@link #MONITOR_REQUEST} is advertised with the subject
* "net.sf.eBusx.monitor" to form this request key.
*/
public static final String MONITOR_REQUEST =
"net.sf.eBusx.monitor.MonitoredObjectRequest";
/**
* Monitor entry publisher name.
*/
private static final String MONITOR_PUBLISHER =
"MonitorPublisher";
/**
* Monitor entry replier name.
*/
private static final String MONITOR_REPLIER =
"MonitorReplier";
//-----------------------------------------------------------
// Statics.
//
/**
* Responsible for publishing monitor notification messages.
*/
private static final MonitorPublisher sPublisher;
/**
* Used to synchronize access to static data.
*/
private static final Lock sMonitorLock =
new ReentrantLock(true);
/**
* Used to assign a unique identifier to a monitored object.
*/
private static final IndexPool sMonitorIdPool =
new IndexPool();
/**
* Since eBus only interacts with objects, create an instance
* of the static {@link MonitorReplier} class to handle
* {@code net.sf.eBusx.monitor.MonitoredObjectRequest}
* messages.
*/
private static final MonitorReplier sReplier;
/**
* Maps the monitored object to its entry.
*/
private static final ConcurrentMap
sMonitoredMap = new ConcurrentHashMap<>();
/**
* Logging subsystem interface.
*/
private static final Logger sLogger =
Logger.getLogger(Monitor.class.getName());
// Static initialization block.
static
{
// "Compile" the message types on start.
DataType.findType(ApplicationInfo.class);
DataType.findType(MonitorUpdate.class);
DataType.findType(MonitoredObjectReply.class);
DataType.findType(MonitoredObjectRequest.class);
DataType.findType(PersistentStatusMessage.class);
DataType.findType(TransientStatusMessage.class);
// Instantiate the monitor object publisher and advertise
// its notification feed.
final CountDownLatch signal = new CountDownLatch(2);
sPublisher = new MonitorPublisher(signal);
EFeed.register(sPublisher);
// Instantiate the monitored object request handler and
// advertise it.
sReplier = new MonitorReplier(signal);
EFeed.register(sReplier);
EFeed.startup(sPublisher);
EFeed.startup(sReplier);
// Wait here for the publisher and replier start-up to
// complete.
try
{
signal.await();
}
catch (InterruptedException interrupt)
{}
} // end of static.
//---------------------------------------------------------------
// Member methods.
//
//-----------------------------------------------------------
// Constructors.
//
/**
* A private default constructor is defined to prevent
* instantiation.
*/
private Monitor()
{}
//
// end of Constructors.
//-----------------------------------------------------------
/**
* Publishes the given application information.
* @param name the application name. May not be {@code null}
* or empty.
* @param version the application version. May not be
* {@code null} or empty.
* @param copyright the application copyright. May be
* {@code null}.
* @param description the application description. May be
* {@code null}.
* @param attributes the application-specific attributes.
* @throws IllegalArgumentException
* if either {@code name} or {@code version} is {@code null}
* or empty.
*/
public static void applicationInfo(final String name,
final String version,
final String copyright,
final String description,
final EField attributes)
{
sPublisher.publish(ApplicationInfo.builder()
.appName(name)
.appVersion(version)
.copyright(copyright)
.description(description)
.attributes(attributes)
.build());
} // end of applicationInfo(String, String, String, String)
/**
* Registers a monitorable object. The object's initial
* persistent status is set to {@link ActionLevel#NO_ACTION},
* "Registered". A {@link Monitorable} object must
* successfully register prior to
* {@link #update(ActionLevel, String, String, Monitorable) updating}
* is status or posting a
* {@link #transientStatus(ActionLevel, String, String, Monitorable) transient} event.
* @param obj register this monitorable object.
* @throws NullPointerException
* if {@code obj} is {@code null}.
* @throws IllegalArgumentException
* if {@code obj} is {@code null} or
* {@link Monitorable#instanceName} returns a {@code null}
* or empty string.
*
* @see #update(ActionLevel, String, String, Monitorable)
* @see #transientStatus(ActionLevel, String, String, Monitorable)
* @see #deregister(Monitorable)
*/
public static void register(final Monitorable obj)
{
final String instanceName =
(Objects.requireNonNull(obj, "obj is null")).instanceName();
if (Strings.isNullOrEmpty(instanceName))
{
throw (
new IllegalArgumentException(
"instance name is either null or empty"));
}
final String typeName = (obj.getClass()).getName();
final MonitorId monitorId =
MonitorId.builder()
.typeName(typeName)
.instanceName(instanceName)
.id(sMonitorIdPool.nextIndex())
.build();
final MonitorEntry entry =
new MonitorEntry(obj, monitorId);
// Is this object already registered?
if (sMonitoredMap.putIfAbsent(obj, entry) == null)
{
// No. Continue with the registration.
if (sLogger.isLoggable(Level.FINE))
{
sLogger.fine(
String.format(
"Registering %s.%s for monitoring.",
typeName,
instanceName));
}
sMonitoredMap.put(obj, entry);
// Have the entry open the persistent and
// transient status feeds.
(entry.mLock).lock();
try
{
EFeed.register(entry);
EFeed.startup(entry);
// Wait here for the entry to start up to
// complete.
while (!entry.isRunning())
{
try
{
(entry.mStartSignal).await();
}
catch (InterruptedException interrupt)
{}
}
}
finally
{
(entry.mLock).unlock();
}
// Tell the world about this new monitored object.
sPublisher.publish(
MonitorUpdate.builder()
.instance(monitorId)
.updateFlag(true)
.build());
}
// Yes, ignore this duplicate registration.
} // end of register(Monitorable)
/**
* Updates the monitorable object on-going status with the
* given parameters.
* @param actionLevel the action level.
* @param actionName the action name.
* @param actionMsg the human-readable action message.
* @param obj the registered monitorable object.
* @throws NullPointerException
* if {@code obj} is {@code null}.
* @throws IllegalArgumentException
* if {@code actionName} is either {@code null} or an empty
* string.
* @throws IllegalStateException
* if {@code obj} is not registered.
*
* @see #transientStatus(ActionLevel, String, String, Monitorable)
* @see #register(Monitorable)
* @see #deregister(Monitorable)
*/
public static void update(final ActionLevel actionLevel,
final String actionName,
final String actionMsg,
final Monitorable obj)
{
Objects.requireNonNull(obj, "obj is null");
if (Strings.isNullOrEmpty(actionName))
{
throw (
new IllegalArgumentException(
"null or empty actionName"));
}
final MonitorEntry entry = sMonitoredMap.get(obj);
// The actionMsg may be null or empty.
// But the monitored object must be registered.
if (entry == null)
{
throw (
new IllegalStateException("obj not registered"));
}
entry.updatePersistent(actionLevel,
actionName,
actionMsg);
} // end of updatePersistent(ActionLevel, String, String, Monitorable)
/**
* Posts a one-time transient event for the given monitorable
* object.
* @param actionLevel the action level.
* @param actionName the action name.
* @param actionMsg the human-readable action message.
* @param obj the registered monitorable object.
* @throws NullPointerException
* if {@code obj} is {@code null}.
* @throws IllegalArgumentException
* if {@code actionName} is either {@code null} or an empty
* string.
* @throws IllegalStateException
* if {@code obj} is not registered.
*
* @see #register(Monitorable)
* @see #update(ActionLevel, String, String, Monitorable)
* @see #deregister(Monitorable)
*/
public static void transientStatus(final ActionLevel actionLevel,
final String actionName,
final String actionMsg,
final Monitorable obj)
{
Objects.requireNonNull(obj, "null obj");
if (Strings.isNullOrEmpty(actionName))
{
throw (
new IllegalArgumentException(
"null or empty actionName"));
}
final MonitorEntry entry = sMonitoredMap.get(obj);
// The actionMsg may be null or empty.
// But the monitored object must be registered.
if (entry == null)
{
throw (
new IllegalStateException("obj not registered"));
}
entry.updateTransient(actionLevel,
actionName,
actionMsg);
} // end of transientStatus(...)
/**
* Removes a registered {@link Monitorable} object from the
* monitor subsystem, retracting its published status and
* transient event feeds.
* @param obj remove this monitorable instance.
* @throws NullPointerException
* if {@code obj} is {@code null}.
*
* @see #update(ActionLevel, String, String, Monitorable)
* @see #transientStatus(ActionLevel, String, String, Monitorable)
* @see #register(Monitorable)
*/
public static void deregister(final Monitorable obj)
{
Objects.requireNonNull(obj, "null obj");
final MonitorEntry entry = sMonitoredMap.remove(obj);
// Is this monitored object currently registered?
if (entry != null)
{
// Yes. Continue with the deregistration.
final MonitorId monitorId = entry.monitorId();
if (sLogger.isLoggable(Level.FINE))
{
sLogger.fine(
String.format(
"Deregistering %s from monitoring.",
monitorId));
}
// Publish and close the monitor entry.
entry.updatePersistent(
ActionLevel.NO_ACTION,
"Deregistered",
"Deregistered from monitor subsystem");
(entry.mLock).lock();
try
{
EFeed.shutdown(entry);
// Wait here for the entry to shutdown to
// complete.
while (entry.isRunning())
{
try
{
(entry.mStopSignal).await();
}
catch (InterruptedException interrupt)
{}
}
}
finally
{
(entry.mLock).unlock();
}
// Tell the world about this change.
sPublisher.publish(
MonitorUpdate.builder()
.instance(monitorId)
.updateFlag(false)
.build());
}
} // end of deregister(Monitorable)
//---------------------------------------------------------------
// Inner classes.
//
/**
* This passive, immutable class is used to encapsulate a
* registered {@link Monitorable} object, its {@link MonitorId}
* and latest PersistentStatus message.
*/
private static class MonitorEntry
implements EPublisher
{
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Locals.
//
/**
* The monitored object. Hold the reference to prevent
* its disappearing.
*/
private final Monitorable mObject;
/**
* The monitored object's identifier.
*/
private final MonitorId mId;
/**
* This lock is acquired when starting and shutting down
* a monitor.
*/
private final Lock mLock;
/**
* Set this signal when {@link #startup()} completes.
*/
private final Condition mStartSignal;
/**
* Set this signal when {@link #shutdown()} completes.
*/
private final Condition mStopSignal;
/**
* Set to {@code true} after monitor entry successfully
* starts; otherwise set to {@code false}.
*/
private boolean mRunFlag;
/**
* The current persistent status level. Initialized to
* {@link ActionLevel#NO_ACTION}.
*/
private ActionLevel mPersistLevel;
/**
* The current persistent action name. Initialized to
* "Registered".
*/
private String mPersistName;
/**
* The current persistent action message. Initialized to
* "".
*/
private String mPersistMessage;
/**
* Publish persistent status messages on this feed.
*/
private EPublishFeed mPersistFeed;
/**
* Publish transient status messages on this feed.
*/
private EPublishFeed mTransientFeed;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
/**
* Creates an entry for the given monitorable object and
* identifier.
* @param object monitored object.
* @param id monitor identifier.
*/
public MonitorEntry(final Monitorable object,
final MonitorId id)
{
mObject = object;
mId = id;
mRunFlag = false;
mLock = new ReentrantLock();
mStartSignal = mLock.newCondition();
mStopSignal = mLock.newCondition();
mPersistLevel = ActionLevel.NO_ACTION;
mPersistName = "Registered";
mPersistMessage =
"Registered with monitor subsystem";
mPersistFeed = null;
mTransientFeed = null;
} // end of MonitorEntry(Monitorable, MonitorId)
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// Get methods.
//
/**
* Returns monitored object.
* @return monitored object.
*/
public Monitorable monitoredObject()
{
return (mObject);
} // end of monitoredObject()
/**
* Returns monitored object identifier.
* @return monitor identifier.
*/
public MonitorId monitorId()
{
return (mId);
} // end of monitorId()
/**
* Returns {@code true} if monitor entry successfully
* started and is running; otherwise returns
* {@code false}.
* @return {@code true} if monitor entry is running.
*/
public boolean isRunning()
{
return (mRunFlag);
} // end of isRunning()
//
// end of Get methods.
//-------------------------------------------------------
//-------------------------------------------------------
// EObject Interface Implementation.
//
/**
* Returns monitor entry instance name.
* @return instance name.
*/
@Override
public String name()
{
return (mId.instanceName);
} // end of name()
/**
* Opens, advertises, and sets the feed state to up for
* both the persistent and transient notification feeds.
* @see #shutdown()
*/
@Override
public void startup()
{
mLock.lock();
try
{
final String subject = mId.toString();
final EMessageKey persistKey =
new EMessageKey(
PersistentStatusMessage.class, subject);
final EMessageKey transientKey =
new EMessageKey(
TransientStatusMessage.class, subject);
mPersistFeed =
(EPublishFeed.builder())
.target(this)
.messageKey(persistKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.build();
mTransientFeed =
(EPublishFeed.builder())
.target(this)
.messageKey(transientKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.build();
mPersistFeed.advertise();
mTransientFeed.advertise();
mPersistFeed.updateFeedState(EFeedState.UP);
mTransientFeed.updateFeedState(EFeedState.UP);
mRunFlag = true;
mStartSignal.signal();
}
finally
{
mLock.unlock();
}
} // end of startup()
/**
* Closes both the persistent and transient status feeds
* if open.
* @see #startup()
*/
@Override
public void shutdown()
{
mLock.lock();
try
{
if (mPersistFeed != null)
{
mPersistFeed.close();
mPersistFeed = null;
}
if (mTransientFeed != null)
{
mTransientFeed.close();
mTransientFeed = null;
}
mRunFlag = false;
mStopSignal.signal();
}
finally
{
mLock.unlock();
}
} // end of shutdown()
//
// end of EObject Interface Implementation.
//-------------------------------------------------------
//-------------------------------------------------------
// EPublisher Interface Implementation.
//
/**
* Informs this publisher that the persistent status feed
* is either up or down. If {@code feedState} is
* {@link EFeedState#UP up}, then sends the current
* persistent state.
* @param feedState the notification feed is either up or
* down.
* @param feed {@code feedState} applies to this
* persistent state feed.
*/
@Override
public void publishStatus(final EFeedState feedState,
final IEPublishFeed feed)
{
// Is the feed up or down?
if (feed == mPersistFeed &&
feedState == EFeedState.UP)
{
// Up. Post the current persistent state.
mPersistFeed.publish(
PersistentStatusMessage.builder()
.subject(mId.toString())
.instance(mId.id)
.actionLevel(mPersistLevel)
.actionName(mPersistName)
.actionMessage(mPersistMessage)
.build());
}
} // end of persistStatus(EFeedState, IEPublishFeed}
//
// end of EPublisher Interface Implementation.
//-------------------------------------------------------
/**
* Updates the monitored objects current persistent
* status information. Posts the persistent status
* message if the feed is up.
* @param level current persistent action level.
* @param actionName current persistent action name.
* @param actionMsg current persistent action message.
*/
private void updatePersistent(final ActionLevel level,
final String actionName,
final String actionMsg)
{
mPersistLevel = level;
mPersistName = actionName;
mPersistMessage = actionMsg;
if (mPersistFeed.isFeedUp())
{
mPersistFeed.publish(
PersistentStatusMessage.builder()
.subject(mId.toString())
.instance(mId.id)
.actionLevel(mPersistLevel)
.actionName(mPersistName)
.actionMessage(mPersistMessage)
.build());
}
} // end of updatePersistent(ActionLevel, String, String)
/**
* Publishes the transient status message is the feed is
* up.
* @param level current transient action level.
* @param actionName current transient action name.
* @param actionMsg current transient action message.
*/
private void updateTransient(final ActionLevel level,
final String actionName,
final String actionMsg)
{
if (mTransientFeed.isFeedUp())
{
mTransientFeed.publish(
TransientStatusMessage.builder()
.subject(mId.toString())
.instance(mId.id)
.actionLevel(level)
.actionName(actionName)
.actionMessage(actionMsg)
.build());
}
} // end of updateTransient(ActionLevel, String, String)
} // end of class MonitorEntry
/**
* The singleton application-level publisher for the JVM.
* Publishes the application information and monitor update
* messages.
*/
private static final class MonitorPublisher
implements EPublisher
{
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Locals.
//
/**
* Publish application information on this feed.
*/
private EPublishFeed mAppInfoFeed;
/**
* Publish monitored state updates on this feed.
*/
private EPublishFeed mUpdateFeed;
/**
* Decrement this signal when start-up is complete and
* then drop it.
*/
private CountDownLatch mSignal;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
/**
* Creates a new monitor notification publisher.
* @param signal decrement this signal when start-up
* completes.
*/
private MonitorPublisher(final CountDownLatch signal)
{
mSignal = signal;
} // end of MonitorPublisher(CountDownLatch)
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// EObject Interface Implementation.
//
/**
* Returns monitor publisher name.
* @return monitor publisher name.
*/
@Override
public String name()
{
return (MONITOR_PUBLISHER);
} // end of name()
/**
* Opens and advertises the publisher feeds. Once open,
* these feeds are not closed.
*/
@Override
public void startup()
{
final EMessageKey appInfoKey =
new EMessageKey(ApplicationInfo.class,
MONITOR_UPDATE_SUBJECT);
final EMessageKey updateKey =
new EMessageKey(
MonitorUpdate.class, MONITOR_UPDATE_SUBJECT);
// Put the publisher feeds in place.
mAppInfoFeed =
(EPublishFeed.builder())
.target(this)
.messageKey(appInfoKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.build();
mUpdateFeed =
(EPublishFeed.builder())
.target(this)
.messageKey(updateKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.build();
mAppInfoFeed.advertise();
mUpdateFeed.advertise();
mAppInfoFeed.updateFeedState(EFeedState.UP);
mUpdateFeed.updateFeedState(EFeedState.UP);
mSignal.countDown();
mSignal = null;
return;
} // end of startup()
// Since this publisher is never shutdown, the shutdown()
// method is not overridden.
//
// end of EObject Interface Implementation.
//-------------------------------------------------------
//-------------------------------------------------------
// EPublisher Interface Implementation.
//
/**
* Informs this publisher that the feed is either up
* or down. Since the feed state is checked each time
* a message is published, this method does nothing.
* @param feedState the notification feed is either up or
* down.
* @param feed {@code feedState} applies to this
* notification feed.
*/
// This callback does nothing and so the method body is
// empty.
@SuppressWarnings({"java:S1186"})
@Override
public void publishStatus(final EFeedState feedState,
final IEPublishFeed feed)
{}
//
// end of EPublisher Interface Implementation.
//-------------------------------------------------------
/**
* Publishes the application information message if the
* feed is up.
* @param msg application information message.
*
* @see #publish(MonitorUpdate)
*/
private void publish(final ApplicationInfo msg)
{
if (mAppInfoFeed.isFeedUp())
{
mAppInfoFeed.publish(msg);
}
} // end of publish(ApplicationInfo)
/**
* Publishes the monitor updatePersistent message is the
* feed is up.
* @param msg monitor updatePersistent message.
*
* @see #publish(ApplicationInfo)
*/
private void publish(final MonitorUpdate msg)
{
if (mUpdateFeed.isFeedUp())
{
mUpdateFeed.publish(msg);
}
} // end of publish(MonitorUpdate)
} // end of class MonitorPublisher
/**
* This class replies to {@link MonitoredObjectRequest}
* messages.
*/
private static final class MonitorReplier
implements EReplier
{
//-----------------------------------------------------------
// Member data.
//
//-------------------------------------------------------
// Locals.
//
/**
* Decrement this signal when start-up is complete and
* then drop it.
*/
private CountDownLatch mSignal;
//-----------------------------------------------------------
// Member methods.
//
//-------------------------------------------------------
// Constructors.
//
/**
* Creates a monitor request handler instance.
* @param signal decrement this signal when start-up
* completes.
*/
private MonitorReplier(final CountDownLatch signal)
{
mSignal = signal;
} // end of MonitorReplier(CountDownLatch)
//
// end of Constructors.
//-------------------------------------------------------
//-------------------------------------------------------
// EObject EPublisher Interface Implementation.
//
/**
* Returns monitor replier name.
* @return monitor replier name.
*/
@Override
public String name()
{
return (MONITOR_REPLIER);
} // end of name()
/**
* Opens and advertises the monitored object request
* reply feed. Once open, the reply feed remains open.
*/
@Override
public void startup()
{
final EMessageKey requestKey =
new EMessageKey(MonitoredObjectRequest.class,
MONITOR_REQUEST);
final EReplyFeed replyFeed =
(EReplyFeed.builder())
.target(this)
.messageKey(requestKey)
.scope(FeedScope.LOCAL_AND_REMOTE)
.build();
replyFeed.advertise();
replyFeed.updateFeedState(EFeedState.UP);
mSignal.countDown();
mSignal = null;
return;
} // end of startup()
// Since this replier is never shutdown, the shutdown()
// method is not overridden.
//
// end of EObject Interface Implementation.
//-------------------------------------------------------
//-------------------------------------------------------
// EReplier Interface Implementation.
//
/**
* Generate a monitored object reply to this
* request.
* @param request post the reply to this request.
*/
@Override
public void request(final ERequest request)
{
final MonitorId[] ids;
sMonitorLock.lock();
try
{
int i = 0;
ids = new MonitorId[sMonitoredMap.size()];
for (MonitorEntry entry : sMonitoredMap.values())
{
ids[i] = entry.monitorId();
++i;
}
}
finally
{
sMonitorLock.unlock();
}
request.reply(
MonitoredObjectReply.builder()
.subject((request.key()).subject())
.replyStatus(ReplyStatus.OK_FINAL)
.instances(ids)
.build());
} // end of request(ERequestb)
/**
* Since a reply is sent as soon as a request is
* received, there is no way it can be canceled.
* @param request cancel this request.
* @param mayRespond ignored.
*/
// This callback does nothing and so the method body is
// empty.
@SuppressWarnings({"java:S1186"})
@Override
public void cancelRequest(final ERequest request,
final boolean mayRespond)
{} // end of cancelRequest(ERequest)
//
// end of EReplier Interface Implementation.
//-------------------------------------------------------
} // end of class MonitorReplier
} // end of class Monitor