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.monitors;
028    
029    import static org.opends.server.loggers.debug.DebugLogger.*;
030    import org.opends.server.loggers.debug.DebugTracer;
031    import org.opends.server.types.DebugLogLevel;
032    
033    import org.opends.server.admin.std.server.MonitorProviderCfg;
034    import org.opends.server.api.AttributeSyntax;
035    import org.opends.server.api.MonitorProvider;
036    import org.opends.server.config.ConfigException;
037    import org.opends.server.core.DirectoryServer;
038    import org.opends.server.protocols.asn1.ASN1OctetString;
039    import org.opends.server.types.Attribute;
040    import org.opends.server.types.AttributeType;
041    import org.opends.server.types.AttributeValue;
042    import org.opends.server.types.InitializationException;
043    import org.opends.server.backends.jeb.RootContainer;
044    
045    import com.sleepycat.je.DatabaseException;
046    import com.sleepycat.je.EnvironmentStats;
047    import com.sleepycat.je.JEVersion;
048    import com.sleepycat.je.LockStats;
049    import com.sleepycat.je.StatsConfig;
050    import com.sleepycat.je.TransactionStats;
051    
052    import java.util.ArrayList;
053    import java.util.LinkedHashSet;
054    import java.lang.reflect.Method;
055    
056    /**
057     * A monitor provider for a Berkeley DB JE environment.
058     * It uses reflection on the environment statistics object
059     * so that we don't need to keep a list of all the stats.
060     */
061    public class DatabaseEnvironmentMonitor
062           extends MonitorProvider<MonitorProviderCfg>
063    {
064      /**
065       * The tracer object for the debug logger.
066       */
067      private static final DebugTracer TRACER = getTracer();
068    
069    
070    
071      /**
072       * The name of this monitor instance.
073       */
074      private String name;
075    
076      /**
077       * The root container to be monitored.
078       */
079      private RootContainer rootContainer;
080    
081      /**
082       * Creates a new database environment monitor.
083       * @param name The monitor instance name.
084       * @param rootContainer A root container handle for the database to be
085       * monitored.
086       */
087      public DatabaseEnvironmentMonitor(String name, RootContainer rootContainer)
088      {
089        super(name + " Monitor Provider");
090    
091    
092        this.name = name;
093        this.rootContainer = rootContainer;
094      }
095    
096    
097    
098      /**
099       * {@inheritDoc}
100       */
101      public void initializeMonitorProvider(MonitorProviderCfg configuration)
102           throws ConfigException, InitializationException
103      {
104      }
105    
106      /**
107       * Retrieves the name of this monitor provider.  It should be unique among all
108       * monitor providers, including all instances of the same monitor provider.
109       *
110       * @return The name of this monitor provider.
111       */
112      public String getMonitorInstanceName()
113      {
114        return name;
115      }
116    
117      /**
118       * Retrieves the length of time in milliseconds that should elapse between
119       * calls to the <CODE>updateMonitorData()</CODE> method.  A negative or zero
120       * return value indicates that the <CODE>updateMonitorData()</CODE> method
121       * should not be periodically invoked.
122       *
123       * @return The length of time in milliseconds that should elapse between
124       *         calls to the <CODE>updateMonitorData()</CODE> method.
125       */
126      public long getUpdateInterval()
127      {
128        return 0;
129      }
130    
131      /**
132       * Performs any processing periodic processing that may be desired to update
133       * the information associated with this monitor.  Note that best-effort
134       * attempts will be made to ensure that calls to this method come
135       * <CODE>getUpdateInterval()</CODE> milliseconds apart, but no guarantees will
136       * be made.
137       */
138      public void updateMonitorData()
139      {
140      }
141    
142      /**
143       * Creates monitor attribute values for a given JE statistics object,
144       * using reflection to call all the getter methods of the statistics object.
145       * The attribute type names of the created attribute values are derived from
146       * the names of the getter methods.
147       * @param monitorAttrs The monitor attribute values are inserted into this
148       * attribute list.
149       * @param stats The JE statistics object.
150       * @param attrPrefix A common prefix for the attribute type names of the
151       * monitor attribute values, to distinguish the attributes of one
152       * type of statistical object from another, and to avoid attribute name
153       * collisions.
154       */
155      private void addAttributesForStatsObject(ArrayList<Attribute> monitorAttrs,
156                                               Object stats, String attrPrefix)
157      {
158        Class c = stats.getClass();
159        Method[] methods = c.getMethods();
160    
161        // Iterate through all the statistic class methods.
162        for (Method method : methods)
163        {
164          // Invoke all the getters returning integer values.
165          if (method.getName().startsWith("get"))
166          {
167            Class<?> returnType = method.getReturnType();
168            if (returnType.equals(int.class) || returnType.equals(long.class))
169            {
170              AttributeSyntax integerSyntax =
171                   DirectoryServer.getDefaultIntegerSyntax();
172    
173              // Remove the 'get' from the method name and add the prefix.
174              String attrName = attrPrefix + method.getName().substring(3);
175    
176              try
177              {
178                // Read the statistic.
179                Object statValue = method.invoke(stats);
180    
181                // Create an attribute from the statistic.
182                AttributeType attrType =
183                     DirectoryServer.getDefaultAttributeType(attrName,
184                                                             integerSyntax);
185                ASN1OctetString valueString =
186                     new ASN1OctetString(String.valueOf(statValue));
187                LinkedHashSet<AttributeValue> values =
188                     new LinkedHashSet<AttributeValue>();
189                values.add(new AttributeValue(valueString, valueString));
190                monitorAttrs.add(new Attribute(attrType, attrName, values));
191    
192              } catch (Exception e)
193              {
194                if (debugEnabled())
195                {
196                  TRACER.debugCaught(DebugLogLevel.ERROR, e);
197                }
198              }
199            }
200          }
201        }
202      }
203    
204      /**
205       * Retrieves a set of attributes containing monitor data that should be
206       * returned to the client if the corresponding monitor entry is requested.
207       *
208       * @return A set of attributes containing monitor data that should be
209       *         returned to the client if the corresponding monitor entry is
210       *         requested.
211       */
212      public ArrayList<Attribute> getMonitorData()
213      {
214        EnvironmentStats environmentStats = null;
215        LockStats lockStats = null;
216        TransactionStats transactionStats = null;
217        StatsConfig statsConfig = new StatsConfig();
218    
219        try
220        {
221          environmentStats = rootContainer.getEnvironmentStats(statsConfig);
222          lockStats = rootContainer.getEnvironmentLockStats(statsConfig);
223          transactionStats =
224              rootContainer.getEnvironmentTransactionStats(statsConfig);
225        } catch (DatabaseException e)
226        {
227          if (debugEnabled())
228          {
229            TRACER.debugCaught(DebugLogLevel.ERROR, e);
230          }
231          return null;
232        }
233    
234        ArrayList<Attribute> monitorAttrs = new ArrayList<Attribute>();
235    
236        String jeVersion = JEVersion.CURRENT_VERSION.getVersionString();
237        AttributeType versionType =
238             DirectoryServer.getDefaultAttributeType("JEVersion");
239        LinkedHashSet<AttributeValue> values = new LinkedHashSet<AttributeValue>();
240        values.add(new AttributeValue(versionType, jeVersion));
241        monitorAttrs.add(new Attribute(versionType, "JEVersion", values));
242    
243        addAttributesForStatsObject(monitorAttrs, environmentStats, "Environment");
244        addAttributesForStatsObject(monitorAttrs, lockStats, "Lock");
245        addAttributesForStatsObject(monitorAttrs, transactionStats, "Transaction");
246    
247        return monitorAttrs;
248      }
249    }