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