/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE
* or https://OpenDS.dev.java.net/OpenDS.LICENSE.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at
* trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
* add the following below this CDDL HEADER, with the fields enclosed
* by brackets "[]" replaced with your own identifying information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2010 Sun Microsystems, Inc.
*/
package org.opends.server.extensions;
import org.opends.server.admin.std.server.MonitorProviderCfg;
import org.opends.server.api.DiskSpaceMonitorHandler;
import org.opends.server.api.MonitorProvider;
import org.opends.server.config.ConfigException;
import org.opends.server.core.DirectoryServer;
import org.opends.server.loggers.ErrorLogger;
import org.opends.server.loggers.debug.DebugTracer;
import org.opends.server.types.*;
import static org.opends.messages.CoreMessages.
ERR_DISK_SPACE_MONITOR_UPDATE_FAILED;
import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
import static org.opends.server.loggers.debug.DebugLogger.getTracer;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
/**
* This class provides an application-wide disk space monitoring service.
* It provides the ability for registered handlers to receive notifications
* when the free disk space falls below a certain threshold.
*
* The handler will only be notified once when when the free space
* have dropped below any of the thresholds. Once the "full" threshold
* have been reached, the handler will not be notified again until the
* free space raises above the "low" threshold.
*/
public class DiskSpaceMonitor extends MonitorProvider<MonitorProviderCfg>
implements Runnable
{
/**
* The tracer object for the debug logger.
*/
private static final DebugTracer TRACER = getTracer();
private volatile File directory;
private volatile long lowThreshold;
private volatile long fullThreshold;
private final DiskSpaceMonitorHandler handler;
private final int interval;
private final TimeUnit unit;
private final String instanceName;
private int lastState = 0;
/**
* Constructs a new DiskSpaceMonitor that will notify the specified
* DiskSpaceMonitorHandler when the specified disk
* falls below the provided thresholds.
*
* @param instanceName A unique name for this monitor.
* @param directory The directory to monitor.
* @param lowThreshold The "low" threshold.
* @param fullThreshold The "full" threshold.
* @param interval The polling interval for checking free space.
* @param unit the time unit of the interval parameter.
* @param handler The handler to get notified when the provided thresholds are
* reached or <code>null</code> if no notification is needed;
*/
public DiskSpaceMonitor(String instanceName, File directory,
long lowThreshold,
long fullThreshold, int interval, TimeUnit unit,
DiskSpaceMonitorHandler handler) {
this.directory = directory;
this.lowThreshold = lowThreshold;
this.fullThreshold = fullThreshold;
this.interval = interval;
this.unit = unit;
this.handler = handler;
this.instanceName = instanceName+",cn=Disk Space Monitor";
}
/**
* Retrieves the directory currently being monitored.
*
* @return The directory currently being monitored.
*/
public File getDirectory() {
return directory;
}
/**
* Sets the directory to monitor.
*
* @param directory The directory to monitor.
*/
public void setDirectory(File directory) {
this.directory = directory;
}
/**
* Retrieves the currently "low" space threshold currently being enforced.
*
* @return The currently "low" space threshold currently being enforced.
*/
public long getLowThreshold() {
return lowThreshold;
}
/**
* Sets the "low" space threshold to enforce.
*
* @param lowThreshold The "low" space threshold to enforce.
*/
public void setLowThreshold(long lowThreshold) {
this.lowThreshold = lowThreshold;
}
/**
* Retrieves the currently full threshold currently being enforced.
*
* @return The currently full space threshold currently being enforced.
*/
public long getFullThreshold() {
return fullThreshold;
}
/**
* Sets the full threshold to enforce.
*
* @param fullThreshold The full space threshold to enforce.
*/
public void setFullThreshold(long fullThreshold) {
this.fullThreshold = fullThreshold;
}
/**
* Retrieves the free space currently on the disk.
*
* @return The free space currently on the disk.
*/
public long getFreeSpace() {
return directory.getUsableSpace();
}
/**
* Indicates if the "full" threshold is reached.
*
* @return <code>true</code> if the free space is lower than the "full"
* threshold or <code>false</code> otherwise.
*/
public boolean isFullThresholdReached()
{
return lastState >= 2;
}
/**
* Indicates if the "low" threshold is reached.
*
* @return <code>true</code> if the free space is lower than the "low"
* threshold or <code>false</code> otherwise.
*/
public boolean isLowThresholdReached()
{
return lastState >= 1;
}
/**
* {@inheritDoc}
*/
@Override
public void initializeMonitorProvider(MonitorProviderCfg configuration)
throws ConfigException, InitializationException {
scheduleUpdate(this, 0, interval, unit);
}
/**
* {@inheritDoc}
*/
@Override
public String getMonitorInstanceName() {
return instanceName;
}
/**
* {@inheritDoc}
*/
@Override
public List<Attribute> getMonitorData() {
ArrayList<Attribute> monitorAttrs = new ArrayList<Attribute>();
AttributeType attrType =
DirectoryServer.getDefaultAttributeType("disk-dir",
DirectoryServer.getDefaultStringSyntax());
monitorAttrs.add(Attributes.create(attrType, directory.getPath()));
attrType =
DirectoryServer.getDefaultAttributeType("disk-free",
DirectoryServer.getDefaultIntegerSyntax());
monitorAttrs.add(Attributes.create(attrType,
String.valueOf(getFreeSpace())));
attrType =
DirectoryServer.getDefaultAttributeType("disk-state",
DirectoryServer.getDefaultStringSyntax());
switch(lastState)
{
case 0 : monitorAttrs.add(Attributes.create(attrType, "normal"));
break;
case 1 : monitorAttrs.add(Attributes.create(attrType, "low"));
break;
case 2 : monitorAttrs.add(Attributes.create(attrType, "full"));
break;
}
return monitorAttrs;
}
/**
* {@inheritDoc}
*/
public void run() {
try
{
long lastFreeSpace = directory.getUsableSpace();
if(debugEnabled())
{
TRACER.debugInfo("Free space for %s: %d, " +
"low threshold: %d, full threshold: %d, state: %d",
directory.getPath(), lastFreeSpace, lowThreshold, fullThreshold,
lastState);
}
if(lastFreeSpace < fullThreshold)
{
if(lastState < 2)
{
if(debugEnabled())
{
TRACER.debugInfo("State change: %d -> %d", lastState, 2);
}
lastState = 2;
if(handler != null)
{
handler.diskFullThresholdReached(this);
}
}
}
else if(lastFreeSpace < lowThreshold)
{
if(lastState < 1)
{
if(debugEnabled())
{
TRACER.debugInfo("State change: %d -> %d", lastState, 1);
}
lastState = 1;
if(handler != null)
{
handler.diskLowThresholdReached(this);
}
}
}
else if(lastState != 0)
{
if(debugEnabled())
{
TRACER.debugInfo("State change: %d -> %d", lastState, 0);
}
lastState = 0;
if(handler != null)
{
handler.diskSpaceRestored(this);
}
}
}
catch(Exception e)
{
ErrorLogger.logError(ERR_DISK_SPACE_MONITOR_UPDATE_FAILED.get(
directory.getPath(), e.toString()));
TRACER.debugCaught(DebugLogLevel.ERROR, e);
}
}
}