001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.api;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.List;
033
034 import org.opends.server.admin.std.server.MonitorProviderCfg;
035 import org.opends.server.config.ConfigException;
036 import org.opends.server.types.Attribute;
037 import org.opends.server.types.DebugLogLevel;
038 import org.opends.server.types.DirectoryConfig;
039 import org.opends.server.types.InitializationException;
040 import org.opends.server.types.ObjectClass;
041
042 import static org.opends.server.loggers.debug.DebugLogger.*;
043 import org.opends.server.loggers.debug.DebugTracer;
044 import static org.opends.server.util.ServerConstants.*;
045
046
047
048 /**
049 * This class defines the set of methods and structures that must be
050 * implemented by a Directory Server module that can provide usage,
051 * performance, availability, or other kinds of monitor information
052 * to clients.
053 *
054 * @param <T> The type of configuration handled by this monitor
055 * provider.
056 */
057 @org.opends.server.types.PublicAPI(
058 stability=org.opends.server.types.StabilityLevel.VOLATILE,
059 mayInstantiate=false,
060 mayExtend=true,
061 mayInvoke=false)
062 public abstract class MonitorProvider<T extends MonitorProviderCfg>
063 extends DirectoryThread
064 {
065 /**
066 * The tracer object for the debug logger.
067 */
068 private static final DebugTracer TRACER = getTracer();
069
070 // Indicates whether a request has been received to stop running.
071 private boolean stopRequested;
072
073 // The thread used to run this monitor provider.
074 private Thread monitorThread;
075
076
077
078 /**
079 * Initializes this monitor provider. Note that no initialization
080 * should be done here, since it should be performed in the
081 * {@code initializeMonitorProvider} class.
082 *
083 * @param threadName The name to use for this thread for debugging
084 * purposes.
085 */
086 protected MonitorProvider(String threadName)
087 {
088 super(threadName);
089
090
091 stopRequested = false;
092 monitorThread = null;
093 }
094
095
096
097 /**
098 * Initializes this monitor provider based on the information in the
099 * provided configuration entry.
100 *
101 * @param configuration The configuration to use to initialize
102 * this monitor provider.
103 *
104 * @throws ConfigException If an unrecoverable problem arises in
105 * the process of performing the
106 * initialization.
107 *
108 * @throws InitializationException If a problem occurs during
109 * initialization that is not
110 * related to the server
111 * configuration.
112 */
113 public abstract void initializeMonitorProvider(T configuration)
114 throws ConfigException, InitializationException;
115
116
117
118 /**
119 * Indicates whether the provided configuration is acceptable for
120 * this monitor provider. It should be possible to call this method
121 * on an uninitialized monitor provider instance in order to
122 * determine whether the monitor provider would be able to use the
123 * provided configuration.
124 * <BR><BR>
125 * Note that implementations which use a subclass of the provided
126 * configuration class will likely need to cast the configuration
127 * to the appropriate subclass type.
128 *
129 * @param configuration The monitor provider configuration
130 * for which to make the determination.
131 * @param unacceptableReasons A list that may be used to hold the
132 * reasons that the provided
133 * configuration is not acceptable.
134 *
135 * @return {@code true} if the provided configuration is acceptable
136 * for this monitor provider, or {@code false} if not.
137 */
138 public boolean isConfigurationAcceptable(
139 MonitorProviderCfg configuration,
140 List<Message> unacceptableReasons)
141 {
142 // This default implementation does not perform any special
143 // validation. It should be overridden by monitor provider
144 // implementations that wish to perform more detailed validation.
145 return true;
146 }
147
148
149
150 /**
151 * Finalizes this monitor provider so that it may be unloaded and
152 * taken out of service. This method should be overridden by any
153 * monitor provider that has resources that should be released when
154 * the monitor is no longer needed. Any monitor that does override
155 * this method must first invoke this version by calling
156 * {@code super.finalizeMonitorProvider}.
157 */
158 public void finalizeMonitorProvider()
159 {
160 // Signal the monitor thread that it should stop.
161 stopRequested = true;
162
163 try
164 {
165 if (monitorThread != null)
166 {
167 monitorThread.interrupt();
168 }
169 }
170 catch (Exception e)
171 {
172 if (debugEnabled())
173 {
174 TRACER.debugCaught(DebugLogLevel.ERROR, e);
175 }
176 }
177 }
178
179
180
181 /**
182 * Retrieves the name of this monitor provider. It should be unique
183 * among all monitor providers, including all instances of the same
184 * monitor provider.
185 *
186 * @return The name of this monitor provider.
187 */
188 public abstract String getMonitorInstanceName();
189
190
191
192 /**
193 * Retrieves the objectclass that should be included in the monitor
194 * entry created from this monitor provider. This may be overridden
195 * by subclasses that wish to include their own custom objectclass
196 * in the monitor entry (e.g., to make it easier to search for
197 * monitor entries of that type). The default implementation
198 * returns the "extensibleObject" objectclass.
199 *
200 * @return The objectclass that should be included in the monitor
201 * entry created from this monitor provider.
202 */
203 public ObjectClass getMonitorObjectClass()
204 {
205 return DirectoryConfig.getObjectClass(OC_EXTENSIBLE_OBJECT_LC,
206 true);
207 }
208
209
210
211 /**
212 * Retrieves the length of time in milliseconds that should elapse
213 * between calls to the {@code updateMonitorData} method. A
214 * negative or zero return value indicates that the
215 * {@code updateMonitorData} method should not be periodically
216 * invoked.
217 *
218 * @return The length of time in milliseconds that should elapse
219 * between calls to the {@code updateMonitorData()} method.
220 */
221 public abstract long getUpdateInterval();
222
223
224
225 /**
226 * Performs any processing periodic processing that may be desired
227 * to update the information associated with this monitor. Note
228 * that best-effort attempts will be made to ensure that calls to
229 * this method come {@code getUpdateInterval} milliseconds apart,
230 * but no guarantees will be made.
231 */
232 public abstract void updateMonitorData();
233
234
235
236 /**
237 * Retrieves a set of attributes containing monitor data that should
238 * be returned to the client if the corresponding monitor entry is
239 * requested.
240 *
241 * @return A set of attributes containing monitor data that should
242 * be returned to the client if the corresponding monitor
243 * entry is requested.
244 */
245 public abstract List<Attribute> getMonitorData();
246
247
248
249 /**
250 * Enters a loop, periodically invoking the
251 * {@code getUpdateInterval} method to updates the data associated
252 * with this monitor.
253 */
254 public final void run()
255 {
256 monitorThread = Thread.currentThread();
257
258
259 // If this monitor should not perform any checks to periodically
260 // update its information, then there is no need to run this
261 // method.
262 if (getUpdateInterval() <= 0)
263 {
264 return;
265 }
266
267
268 // Set the name of this thread for debugging purposes.
269 setName(getMonitorInstanceName() + " Monitor Provider");
270
271
272 // Operate in a loop until it is detected that the server is
273 // shutting down.
274 while (! stopRequested)
275 {
276 long stopSleepTime =
277 System.currentTimeMillis() + getUpdateInterval();
278 try
279 {
280 updateMonitorData();
281 }
282 catch (Exception e)
283 {
284 if (debugEnabled())
285 {
286 TRACER.debugCaught(DebugLogLevel.ERROR, e);
287 }
288 }
289
290 long remainingSleepTime =
291 stopSleepTime - System.currentTimeMillis();
292 while ((! stopRequested) && (remainingSleepTime > 0))
293 {
294 if (remainingSleepTime > 1000)
295 {
296 try
297 {
298 Thread.sleep(1000);
299 } catch (Exception e) {}
300 }
301 else
302 {
303 try
304 {
305 Thread.sleep(remainingSleepTime);
306 } catch (Exception e) {}
307 }
308
309 remainingSleepTime =
310 stopSleepTime - System.currentTimeMillis();
311 }
312 }
313 }
314 }
315