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.backends;
028
029
030
031 import java.util.ArrayList;
032 import java.util.HashMap;
033 import java.util.HashSet;
034 import java.util.LinkedHashMap;
035 import java.util.LinkedHashSet;
036 import java.util.List;
037
038 import org.opends.messages.Message;
039 import org.opends.server.admin.Configuration;
040 import org.opends.server.admin.server.ConfigurationChangeListener;
041 import org.opends.server.admin.std.server.MonitorBackendCfg;
042 import org.opends.server.admin.std.server.MonitorProviderCfg;
043 import org.opends.server.api.Backend;
044 import org.opends.server.api.MonitorProvider;
045 import org.opends.server.config.ConfigEntry;
046 import org.opends.server.config.ConfigException;
047 import org.opends.server.core.AddOperation;
048 import org.opends.server.core.DeleteOperation;
049 import org.opends.server.core.DirectoryServer;
050 import org.opends.server.core.ModifyOperation;
051 import org.opends.server.core.ModifyDNOperation;
052 import org.opends.server.core.SearchOperation;
053 import org.opends.server.loggers.debug.DebugTracer;
054 import org.opends.server.protocols.asn1.ASN1OctetString;
055 import org.opends.server.types.Attribute;
056 import org.opends.server.types.AttributeType;
057 import org.opends.server.types.AttributeValue;
058 import org.opends.server.types.BackupConfig;
059 import org.opends.server.types.BackupDirectory;
060 import org.opends.server.types.ConditionResult;
061 import org.opends.server.types.ConfigChangeResult;
062 import org.opends.server.types.DebugLogLevel;
063 import org.opends.server.types.DirectoryException;
064 import org.opends.server.types.DN;
065 import org.opends.server.types.Entry;
066 import org.opends.server.types.IndexType;
067 import org.opends.server.types.InitializationException;
068 import org.opends.server.types.LDIFExportConfig;
069 import org.opends.server.types.LDIFImportConfig;
070 import org.opends.server.types.LDIFImportResult;
071 import org.opends.server.types.ObjectClass;
072 import org.opends.server.types.RDN;
073 import org.opends.server.types.RestoreConfig;
074 import org.opends.server.types.ResultCode;
075 import org.opends.server.types.SearchFilter;
076 import org.opends.server.types.SearchScope;
077 import org.opends.server.util.DynamicConstants;
078 import org.opends.server.util.LDIFWriter;
079 import org.opends.server.util.TimeThread;
080 import org.opends.server.util.Validator;
081
082 import static org.opends.server.config.ConfigConstants.*;
083 import static org.opends.server.loggers.debug.DebugLogger.*;
084 import static org.opends.messages.BackendMessages.*;
085 import static org.opends.messages.ConfigMessages.*;
086 import static org.opends.server.util.ServerConstants.*;
087 import static org.opends.server.util.StaticUtils.*;
088
089
090
091 /**
092 * This class defines a backend to hold Directory Server monitor entries. It
093 * will not actually store anything, but upon request will retrieve the
094 * requested monitor and dynamically generate the associated entry. It will
095 * also construct a base monitor entry with some useful server-wide data.
096 */
097 public class MonitorBackend
098 extends Backend
099 implements ConfigurationChangeListener<MonitorBackendCfg>
100 {
101 /**
102 * The tracer object for the debug logger.
103 */
104 private static final DebugTracer TRACER = getTracer();
105
106
107
108 // The set of user-defined attributes that will be included in the base
109 // monitor entry.
110 private ArrayList<Attribute> userDefinedAttributes;
111
112 // The set of objectclasses that will be used in monitor entries.
113 private HashMap<ObjectClass,String> monitorObjectClasses;
114
115 // The DN of the configuration entry for this backend.
116 private DN configEntryDN;
117
118 // The current configuration state.
119 private MonitorBackendCfg currentConfig;
120
121 // The DN for the base monitor entry.
122 private DN baseMonitorDN;
123
124 // The set of base DNs for this backend.
125 private DN[] baseDNs;
126
127 // The set of supported controls for this backend.
128 private HashSet<String> supportedControls;
129
130 // The set of supported features for this backend.
131 private HashSet<String> supportedFeatures;
132
133
134
135 /**
136 * Creates a new backend with the provided information. All backend
137 * implementations must implement a default constructor that use
138 * <CODE>super()</CODE> to invoke this constructor.
139 */
140 public MonitorBackend()
141 {
142 super();
143
144 // Perform all initialization in initializeBackend.
145 }
146
147
148 /**
149 * {@inheritDoc}
150 */
151 @Override()
152 public void configureBackend(Configuration config)
153 throws ConfigException
154 {
155 Validator.ensureNotNull(config);
156 Validator.ensureTrue(config instanceof MonitorBackendCfg);
157
158 MonitorBackendCfg cfg = (MonitorBackendCfg)config;
159 ConfigEntry configEntry = DirectoryServer.getConfigEntry(cfg.dn());
160
161
162 // Make sure that a configuration entry was provided. If not, then we will
163 // not be able to complete initialization.
164 if (configEntry == null)
165 {
166 Message message = ERR_MONITOR_CONFIG_ENTRY_NULL.get();
167 throw new ConfigException(message);
168 }
169
170 configEntryDN = configEntry.getDN();
171
172
173 // Get the set of user-defined attributes for the configuration entry. Any
174 // attributes that we don't recognize will be included directly in the base
175 // monitor entry.
176 userDefinedAttributes = new ArrayList<Attribute>();
177 for (List<Attribute> attrs :
178 configEntry.getEntry().getUserAttributes().values())
179 {
180 for (Attribute a : attrs)
181 {
182 if (! isMonitorConfigAttribute(a))
183 {
184 userDefinedAttributes.add(a);
185 }
186 }
187 }
188 for (List<Attribute> attrs :
189 configEntry.getEntry().getOperationalAttributes().values())
190 {
191 for (Attribute a : attrs)
192 {
193 if (! isMonitorConfigAttribute(a))
194 {
195 userDefinedAttributes.add(a);
196 }
197 }
198 }
199
200
201 // Construct the set of objectclasses to include in the base monitor entry.
202 monitorObjectClasses = new LinkedHashMap<ObjectClass,String>(2);
203 ObjectClass topOC = DirectoryServer.getObjectClass(OC_TOP, true);
204 monitorObjectClasses.put(topOC, OC_TOP);
205
206 ObjectClass monitorOC = DirectoryServer.getObjectClass(OC_MONITOR_ENTRY,
207 true);
208 monitorObjectClasses.put(monitorOC, OC_MONITOR_ENTRY);
209
210
211 // Define an empty sets for the supported controls and features.
212 supportedControls = new HashSet<String>(0);
213 supportedFeatures = new HashSet<String>(0);
214
215 // Create the set of base DNs that we will handle. In this case, it's just
216 // the DN of the base monitor entry.
217 try
218 {
219 baseMonitorDN = DN.decode(DN_MONITOR_ROOT);
220 }
221 catch (Exception e)
222 {
223 if (debugEnabled())
224 {
225 TRACER.debugCaught(DebugLogLevel.ERROR, e);
226 }
227
228 Message message =
229 ERR_MONITOR_CANNOT_DECODE_MONITOR_ROOT_DN.get(getExceptionMessage(e));
230 throw new ConfigException(message, e);
231 }
232
233 // FIXME -- Deal with this more correctly.
234 this.baseDNs = new DN[] { baseMonitorDN };
235
236
237 currentConfig = cfg;
238 }
239
240
241
242 /**
243 * {@inheritDoc}
244 */
245 @Override()
246 public void initializeBackend()
247 throws ConfigException, InitializationException
248 {
249 // Register with the Directory Server as a configurable component.
250 currentConfig.addMonitorChangeListener(this);
251
252
253 // Register the monitor base as a private suffix.
254 try
255 {
256 DirectoryServer.registerBaseDN(baseMonitorDN, this, true);
257 }
258 catch (Exception e)
259 {
260 if (debugEnabled())
261 {
262 TRACER.debugCaught(DebugLogLevel.ERROR, e);
263 }
264
265 Message message = ERR_BACKEND_CANNOT_REGISTER_BASEDN.get(
266 baseMonitorDN.toString(), getExceptionMessage(e));
267 throw new InitializationException(message, e);
268 }
269 }
270
271
272
273 /**
274 * {@inheritDoc}
275 */
276 @Override()
277 public void finalizeBackend()
278 {
279 currentConfig.removeMonitorChangeListener(this);
280
281 try
282 {
283 DirectoryServer.deregisterBaseDN(baseMonitorDN);
284 }
285 catch (Exception e)
286 {
287 if (debugEnabled())
288 {
289 TRACER.debugCaught(DebugLogLevel.ERROR, e);
290 }
291 }
292 }
293
294
295
296 /**
297 * Indicates whether the provided attribute is one that is used in the
298 * configuration of this backend.
299 *
300 * @param attribute The attribute for which to make the determination.
301 *
302 * @return <CODE>true</CODE> if the provided attribute is one that is used in
303 * the configuration of this backend, <CODE>false</CODE> if not.
304 */
305 private boolean isMonitorConfigAttribute(Attribute attribute)
306 {
307 AttributeType attrType = attribute.getAttributeType();
308 if (attrType.hasName(ATTR_COMMON_NAME) ||
309 attrType.hasName(ATTR_BACKEND_ENABLED.toLowerCase()) ||
310 attrType.hasName(ATTR_BACKEND_CLASS.toLowerCase()) ||
311 attrType.hasName(ATTR_BACKEND_BASE_DN.toLowerCase()) ||
312 attrType.hasName(ATTR_BACKEND_ID.toLowerCase()) ||
313 attrType.hasName(ATTR_BACKEND_WRITABILITY_MODE.toLowerCase()))
314 {
315 return true;
316 }
317
318 return false;
319 }
320
321
322
323 /**
324 * {@inheritDoc}
325 */
326 @Override()
327 public DN[] getBaseDNs()
328 {
329 return baseDNs;
330 }
331
332
333
334 /**
335 * {@inheritDoc}
336 */
337 @Override()
338 public long getEntryCount()
339 {
340 return DirectoryServer.getMonitorProviders().size() + 1;
341 }
342
343
344
345 /**
346 * {@inheritDoc}
347 */
348 @Override()
349 public boolean isLocal()
350 {
351 // For the purposes of this method, this is a local backend.
352 return true;
353 }
354
355
356
357 /**
358 * {@inheritDoc}
359 */
360 @Override()
361 public boolean isIndexed(AttributeType attributeType, IndexType indexType)
362 {
363 // All searches in this backend will always be considered indexed.
364 return true;
365 }
366
367
368
369 /**
370 * {@inheritDoc}
371 */
372 @Override()
373 public ConditionResult hasSubordinates(DN entryDN)
374 throws DirectoryException
375 {
376 long ret = numSubordinates(entryDN, false);
377 if(ret < 0)
378 {
379 return ConditionResult.UNDEFINED;
380 }
381 else if(ret == 0)
382 {
383 return ConditionResult.FALSE;
384 }
385 else
386 {
387 return ConditionResult.TRUE;
388 }
389 }
390
391
392
393 /**
394 * {@inheritDoc}
395 */
396 @Override()
397 public long numSubordinates(DN entryDN, boolean subtree)
398 throws DirectoryException
399 {
400 // If the requested entry was null, then return undefined.
401 if (entryDN == null)
402 {
403 return -1;
404 }
405
406
407 // If the requested entry was the monitor base entry, then return
408 // the number of monitor providers.
409 if (entryDN.equals(baseMonitorDN))
410 {
411 // This backend is only 1 level deep so the count is the same for
412 // subtree and immediate subordinates.
413 return DirectoryServer.getMonitorProviders().size();
414 }
415
416
417 // See if the monitor base entry is the immediate parent for the requested
418 // entry. If not, then its undefined.
419 DN parentDN = entryDN.getParentDNInSuffix();
420 if ((parentDN == null) || (! parentDN.equals(baseMonitorDN)))
421 {
422 return -1;
423 }
424
425
426 // Get the RDN for the requested DN and make sure it is single-valued.
427 RDN entryRDN = entryDN.getRDN();
428 if (entryRDN.isMultiValued())
429 {
430 return -1;
431 }
432
433
434 // Get the RDN value and see if it matches the instance name for one of
435 // the directory server monitor providers.
436 String rdnValue = entryRDN.getAttributeValue(0).getStringValue();
437 MonitorProvider<? extends MonitorProviderCfg> monitorProvider =
438 DirectoryServer.getMonitorProvider(rdnValue.toLowerCase());
439 if (monitorProvider == null)
440 {
441 return -1;
442 }
443
444 return 0;
445 }
446
447
448
449 /**
450 * {@inheritDoc}
451 */
452 @Override()
453 public Entry getEntry(DN entryDN)
454 throws DirectoryException
455 {
456 // If the requested entry was null, then throw an exception.
457 if (entryDN == null)
458 {
459 Message message = ERR_MONITOR_GET_ENTRY_NULL.get();
460 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
461 message);
462 }
463
464
465 // If the requested entry was the monitor base entry, then retrieve it.
466 if (entryDN.equals(baseMonitorDN))
467 {
468 return getBaseMonitorEntry();
469 }
470
471
472 // See if the monitor base entry is the immediate parent for the requested
473 // entry. If not, then throw an exception.
474 DN parentDN = entryDN.getParentDNInSuffix();
475 if ((parentDN == null) || (! parentDN.equals(baseMonitorDN)))
476 {
477 if (baseMonitorDN.isAncestorOf(entryDN))
478 {
479 Message message = ERR_MONITOR_BASE_TOO_DEEP.get(
480 String.valueOf(entryDN), String.valueOf(baseMonitorDN));
481 throw new DirectoryException(
482 ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
483 }
484 else
485 {
486 Message message = ERR_MONITOR_INVALID_BASE.get(
487 String.valueOf(entryDN), String.valueOf(baseMonitorDN));
488 throw new DirectoryException(ResultCode.NO_SUCH_OBJECT, message);
489 }
490 }
491
492
493 // Get the RDN for the requested DN and make sure it is single-valued.
494 RDN entryRDN = entryDN.getRDN();
495 if (entryRDN.isMultiValued())
496 {
497 Message message =
498 ERR_MONITOR_MULTIVALUED_RDN.get(String.valueOf(entryDN));
499 throw new DirectoryException(
500 ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
501 }
502
503
504 // Get the RDN value and see if it matches the instance name for one of
505 // the directory server monitor providers.
506 String rdnValue = entryRDN.getAttributeValue(0).getStringValue();
507 MonitorProvider<? extends MonitorProviderCfg> monitorProvider =
508 DirectoryServer.getMonitorProvider(rdnValue.toLowerCase());
509 if (monitorProvider == null)
510 {
511 Message message =
512 ERR_MONITOR_NO_SUCH_PROVIDER.get(String.valueOf(rdnValue));
513 throw new DirectoryException(
514 ResultCode.NO_SUCH_OBJECT, message, baseMonitorDN, null);
515 }
516
517
518 // Take the data from the monitor provider and stuff it into an entry.
519 return getMonitorEntry(entryDN, monitorProvider);
520 }
521
522
523
524 /**
525 * {@inheritDoc}
526 */
527 @Override()
528 public boolean entryExists(DN entryDN)
529 throws DirectoryException
530 {
531 if (entryDN.equals(baseMonitorDN))
532 {
533 return true;
534 }
535
536 DN parentDN = entryDN.getParentDNInSuffix();
537 if ((parentDN == null) || (! parentDN.equals(baseMonitorDN)))
538 {
539 return false;
540 }
541
542 RDN rdn = entryDN.getRDN();
543 if (rdn.isMultiValued())
544 {
545 return false;
546 }
547
548 String rdnValue = rdn.getAttributeValue(0).getStringValue();
549 MonitorProvider monitorProvider =
550 DirectoryServer.getMonitorProvider(toLowerCase(rdnValue));
551 return (monitorProvider != null);
552 }
553
554
555
556 /**
557 * Retrieves the base monitor entry for the Directory Server.
558 *
559 * @return The base monitor entry for the Directory Server.
560 */
561 public Entry getBaseMonitorEntry()
562 {
563 HashMap<ObjectClass,String> monitorClasses =
564 new LinkedHashMap<ObjectClass,String>(3);
565 monitorClasses.putAll(monitorObjectClasses);
566
567 ObjectClass extensibleObjectOC =
568 DirectoryServer.getObjectClass(OC_EXTENSIBLE_OBJECT_LC, true);
569 monitorClasses.put(extensibleObjectOC, OC_EXTENSIBLE_OBJECT);
570
571 HashMap<AttributeType,List<Attribute>> monitorUserAttrs =
572 new LinkedHashMap<AttributeType,List<Attribute>>();
573
574 HashMap<AttributeType,List<Attribute>> monitorOperationalAttrs =
575 new LinkedHashMap<AttributeType,List<Attribute>>();
576
577
578 // Add the "cn" attribute.
579 Attribute cnAttr = createAttribute(ATTR_COMMON_NAME, ATTR_COMMON_NAME,
580 "monitor");
581 ArrayList<Attribute> cnList = new ArrayList<Attribute>(1);
582 cnList.add(cnAttr);
583 monitorUserAttrs.put(cnAttr.getAttributeType(), cnList);
584
585
586 // Add the server product name.
587 Attribute productNameAttr = createAttribute(ATTR_PRODUCT_NAME,
588 ATTR_PRODUCT_NAME_LC,
589 DynamicConstants.PRODUCT_NAME);
590 ArrayList<Attribute> productNameList = new ArrayList<Attribute>(1);
591 productNameList.add(productNameAttr);
592 monitorUserAttrs.put(productNameAttr.getAttributeType(), productNameList);
593
594
595 // Add the vendor name.
596 Attribute vendorNameAttr = createAttribute(ATTR_VENDOR_NAME,
597 ATTR_VENDOR_NAME_LC,
598 SERVER_VENDOR_NAME);
599 ArrayList<Attribute> vendorNameList = new ArrayList<Attribute>(1);
600 vendorNameList.add(vendorNameAttr);
601 monitorUserAttrs.put(vendorNameAttr.getAttributeType(), vendorNameList);
602
603
604 // Add the vendor version.
605 Attribute versionAttr = createAttribute(ATTR_VENDOR_VERSION,
606 ATTR_VENDOR_VERSION_LC,
607 DirectoryServer.getVersionString());
608 ArrayList<Attribute> versionList = new ArrayList<Attribute>(1);
609 versionList.add(versionAttr);
610 monitorUserAttrs.put(versionAttr.getAttributeType(), versionList);
611
612
613 // Add the server startup time.
614 Attribute startTimeAttr =
615 createAttribute(ATTR_START_TIME, ATTR_START_TIME_LC,
616 DirectoryServer.getStartTimeUTC());
617 ArrayList<Attribute> startTimeList = new ArrayList<Attribute>(1);
618 startTimeList.add(startTimeAttr);
619 monitorUserAttrs.put(startTimeAttr.getAttributeType(), startTimeList);
620
621
622 // Add the current time.
623 Attribute currentTimeAttr =
624 createAttribute(ATTR_CURRENT_TIME, ATTR_CURRENT_TIME_LC,
625 TimeThread.getGMTTime());
626 ArrayList<Attribute> currentTimeList = new ArrayList<Attribute>(1);
627 currentTimeList.add(currentTimeAttr);
628 monitorUserAttrs.put(currentTimeAttr.getAttributeType(), currentTimeList);
629
630
631 // Add the uptime as a human-readable string.
632 long upSeconds =
633 ((System.currentTimeMillis() - DirectoryServer.getStartTime()) / 1000);
634 long upDays = (upSeconds / 86400);
635 upSeconds %= 86400;
636 long upHours = (upSeconds / 3600);
637 upSeconds %= 3600;
638 long upMinutes = (upSeconds / 60);
639 upSeconds %= 60;
640 Message upTimeStr =
641 INFO_MONITOR_UPTIME.get(upDays, upHours, upMinutes, upSeconds);
642 Attribute upTimeAttr = createAttribute(ATTR_UP_TIME, ATTR_UP_TIME_LC,
643 upTimeStr.toString());
644 ArrayList<Attribute> upTimeList = new ArrayList<Attribute>(1);
645 upTimeList.add(upTimeAttr);
646 monitorUserAttrs.put(upTimeAttr.getAttributeType(), upTimeList);
647
648
649 // Add the number of connections currently established.
650 long currentConns = DirectoryServer.getCurrentConnections();
651 Attribute currentConnsAttr = createAttribute(ATTR_CURRENT_CONNS,
652 ATTR_CURRENT_CONNS_LC,
653 String.valueOf(currentConns));
654 ArrayList<Attribute> currentConnsList = new ArrayList<Attribute>(1);
655 currentConnsList.add(currentConnsAttr);
656 monitorUserAttrs.put(currentConnsAttr.getAttributeType(), currentConnsList);
657
658
659 // Add the maximum number of connections established at one time.
660 long maxConns = DirectoryServer.getMaxConnections();
661 Attribute maxConnsAttr = createAttribute(ATTR_MAX_CONNS,
662 ATTR_MAX_CONNS_LC,
663 String.valueOf(maxConns));
664 ArrayList<Attribute> maxConnsList = new ArrayList<Attribute>(1);
665 maxConnsList.add(maxConnsAttr);
666 monitorUserAttrs.put(maxConnsAttr.getAttributeType(), maxConnsList);
667
668
669 // Add the total number of connections the server has accepted.
670 long totalConns = DirectoryServer.getTotalConnections();
671 Attribute totalConnsAttr = createAttribute(ATTR_TOTAL_CONNS,
672 ATTR_TOTAL_CONNS_LC,
673 String.valueOf(totalConns));
674 ArrayList<Attribute> totalConnsList = new ArrayList<Attribute>(1);
675 totalConnsList.add(totalConnsAttr);
676 monitorUserAttrs.put(totalConnsAttr.getAttributeType(), totalConnsList);
677
678
679 // Add all the user-defined attributes.
680 for (Attribute a : userDefinedAttributes)
681 {
682 AttributeType type = a.getAttributeType();
683
684 if (type.isOperational())
685 {
686 List<Attribute> attrs = monitorOperationalAttrs.get(type);
687 if (attrs == null)
688 {
689 attrs = new ArrayList<Attribute>();
690 attrs.add(a);
691 monitorOperationalAttrs.put(type, attrs);
692 }
693 else
694 {
695 attrs.add(a);
696 }
697 }
698 else
699 {
700 List<Attribute> attrs = monitorUserAttrs.get(type);
701 if (attrs == null)
702 {
703 attrs = new ArrayList<Attribute>();
704 attrs.add(a);
705 monitorUserAttrs.put(type, attrs);
706 }
707 else
708 {
709 attrs.add(a);
710 }
711 }
712 }
713
714
715 // Construct and return the entry.
716 Entry e = new Entry(baseMonitorDN, monitorClasses, monitorUserAttrs,
717 monitorOperationalAttrs);
718 e.processVirtualAttributes();
719 return e;
720 }
721
722
723
724 /**
725 * Generates and returns a monitor entry based on the contents of the
726 * provided monitor provider.
727 *
728 * @param entryDN The DN to use for the entry.
729 * @param monitorProvider The monitor provider to use to obtain the
730 * information for the entry.
731 *
732 * @return The monitor entry generated from the information in the provided
733 * monitor provider.
734 */
735 private Entry getMonitorEntry(DN entryDN,
736 MonitorProvider<? extends MonitorProviderCfg>
737 monitorProvider)
738 {
739 HashMap<ObjectClass,String> monitorClasses =
740 new LinkedHashMap<ObjectClass,String>(3);
741 monitorClasses.putAll(monitorObjectClasses);
742
743 ObjectClass monitorOC = monitorProvider.getMonitorObjectClass();
744 monitorClasses.put(monitorOC, monitorOC.getPrimaryName());
745
746 List<Attribute> monitorAttrs = monitorProvider.getMonitorData();
747 HashMap<AttributeType,List<Attribute>> attrMap =
748 new LinkedHashMap<AttributeType,List<Attribute>>(
749 monitorAttrs.size()+1);
750
751
752 // Make sure to include the RDN attribute.
753 RDN entryRDN = entryDN.getRDN();
754 AttributeType rdnType = entryRDN.getAttributeType(0);
755 AttributeValue rdnValue = entryRDN.getAttributeValue(0);
756
757 LinkedHashSet<AttributeValue> rdnValues =
758 new LinkedHashSet<AttributeValue>(1);
759 rdnValues.add(rdnValue);
760
761 Attribute rdnAttr = new Attribute(rdnType, entryRDN.getAttributeName(0),
762 rdnValues);
763 ArrayList<Attribute> rdnList = new ArrayList<Attribute>(1);
764 rdnList.add(rdnAttr);
765 attrMap.put(rdnType, rdnList);
766
767
768 // Take the rest of the information from the monitor data.
769 for (Attribute a : monitorAttrs)
770 {
771 AttributeType type = a.getAttributeType();
772
773 List<Attribute> attrs = attrMap.get(type);
774 if (attrs == null)
775 {
776 attrs = new ArrayList<Attribute>();
777 attrs.add(a);
778 attrMap.put(type, attrs);
779 }
780 else
781 {
782 attrs.add(a);
783 }
784 }
785
786 Entry e = new Entry(entryDN, monitorClasses, attrMap,
787 new HashMap<AttributeType,List<Attribute>>(0));
788 e.processVirtualAttributes();
789 return e;
790 }
791
792
793
794 /**
795 * Creates an attribute for a monitor entry with the following criteria.
796 *
797 * @param name The name for the attribute.
798 * @param lowerName The name for the attribute formatted in all lowercase
799 * characters.
800 * @param value The value to use for the attribute.
801 *
802 * @return The constructed attribute.
803 */
804 private Attribute createAttribute(String name, String lowerName,
805 String value)
806 {
807 AttributeType type = DirectoryServer.getAttributeType(lowerName);
808 if (type == null)
809 {
810 type = DirectoryServer.getDefaultAttributeType(name);
811 }
812
813 LinkedHashSet<AttributeValue> attrValues =
814 new LinkedHashSet<AttributeValue>(1);
815 attrValues.add(new AttributeValue(type, new ASN1OctetString(value)));
816
817 return new Attribute(type, name, attrValues);
818 }
819
820
821
822 /**
823 * {@inheritDoc}
824 */
825 @Override()
826 public void addEntry(Entry entry, AddOperation addOperation)
827 throws DirectoryException
828 {
829 Message message =
830 ERR_MONITOR_ADD_NOT_SUPPORTED.get(String.valueOf(entry.getDN()));
831 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
832 }
833
834
835
836 /**
837 * {@inheritDoc}
838 */
839 @Override()
840 public void deleteEntry(DN entryDN, DeleteOperation deleteOperation)
841 throws DirectoryException
842 {
843 Message message =
844 ERR_MONITOR_DELETE_NOT_SUPPORTED.get(String.valueOf(entryDN));
845 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
846 }
847
848
849
850 /**
851 * {@inheritDoc}
852 */
853 @Override()
854 public void replaceEntry(Entry entry, ModifyOperation modifyOperation)
855 throws DirectoryException
856 {
857 Message message = ERR_MONITOR_MODIFY_NOT_SUPPORTED.get(
858 String.valueOf(entry.getDN()), String.valueOf(configEntryDN));
859 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
860 }
861
862
863
864 /**
865 * {@inheritDoc}
866 */
867 @Override()
868 public void renameEntry(DN currentDN, Entry entry,
869 ModifyDNOperation modifyDNOperation)
870 throws DirectoryException
871 {
872 Message message =
873 ERR_MONITOR_MODIFY_DN_NOT_SUPPORTED.get(String.valueOf(currentDN));
874 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
875 }
876
877
878
879 /**
880 * {@inheritDoc}
881 */
882 @Override()
883 public void search(SearchOperation searchOperation)
884 throws DirectoryException
885 {
886 // Get the base entry for the search, if possible. If it doesn't exist,
887 // then this will throw an exception.
888 DN baseDN = searchOperation.getBaseDN();
889 Entry baseEntry = getEntry(baseDN);
890
891
892 // Figure out whether the base is the monitor base entry or one of its
893 // children for a specific monitor.
894 SearchScope scope = searchOperation.getScope();
895 SearchFilter filter = searchOperation.getFilter();
896 if (baseMonitorDN.equals(baseDN))
897 {
898 // If it is a base-level or subtree search, then we need to look at the
899 // base monitor entry.
900 if ((scope == SearchScope.BASE_OBJECT) ||
901 (scope == SearchScope.WHOLE_SUBTREE))
902 {
903 if (filter.matchesEntry(baseEntry))
904 {
905 searchOperation.returnEntry(baseEntry, null);
906 }
907
908
909 // If it is a base-level search, then we're done.
910 if (scope == SearchScope.BASE_OBJECT)
911 {
912 return;
913 }
914 }
915
916
917 // Iterate through all of the monitor providers defined in the server.
918 // Get an entry for each and compare it against the filter.
919 for (MonitorProvider<? extends MonitorProviderCfg> monitorProvider :
920 DirectoryServer.getMonitorProviders().values())
921 {
922 DN providerDN = DirectoryServer.getMonitorProviderDN(monitorProvider);
923 Entry monitorEntry = getMonitorEntry(providerDN, monitorProvider);
924 if (filter.matchesEntry(monitorEntry))
925 {
926 searchOperation.returnEntry(monitorEntry, null);
927 }
928 }
929 }
930 else
931 {
932 // Look at the scope for the search. We only need to return something if
933 // it is a base-level or subtree search.
934 if ((scope == SearchScope.BASE_OBJECT) ||
935 (scope == SearchScope.WHOLE_SUBTREE))
936 {
937 if (filter.matchesEntry(baseEntry))
938 {
939 searchOperation.returnEntry(baseEntry, null);
940 }
941 }
942 }
943 }
944
945
946
947 /**
948 * {@inheritDoc}
949 */
950 @Override()
951 public HashSet<String> getSupportedControls()
952 {
953 return supportedControls;
954 }
955
956
957
958 /**
959 * {@inheritDoc}
960 */
961 @Override()
962 public HashSet<String> getSupportedFeatures()
963 {
964 return supportedFeatures;
965 }
966
967
968
969 /**
970 * {@inheritDoc}
971 */
972 @Override()
973 public boolean supportsLDIFExport()
974 {
975 // We can export all the monitor entries as a point-in-time snapshot.
976 // TODO implementation of export is incomplete
977 // TODO export-ldif reports nonsense for upTime etc.
978 return false;
979 }
980
981
982
983 /**
984 * {@inheritDoc}
985 */
986 @Override()
987 public void exportLDIF(LDIFExportConfig exportConfig)
988 throws DirectoryException
989 {
990 // TODO export-ldif reports nonsense for upTime etc.
991
992 // Create the LDIF writer.
993 LDIFWriter ldifWriter;
994 try
995 {
996 ldifWriter = new LDIFWriter(exportConfig);
997 }
998 catch (Exception e)
999 {
1000 if (debugEnabled())
1001 {
1002 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1003 }
1004
1005 Message message = ERR_ROOTDSE_UNABLE_TO_CREATE_LDIF_WRITER.get(
1006 stackTraceToSingleLineString(e));
1007 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
1008 message);
1009 }
1010
1011
1012 // Write the base monitor entry to the LDIF.
1013 try
1014 {
1015 ldifWriter.writeEntry(getBaseMonitorEntry());
1016 }
1017 catch (Exception e)
1018 {
1019 if (debugEnabled())
1020 {
1021 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1022 }
1023
1024 try
1025 {
1026 ldifWriter.close();
1027 }
1028 catch (Exception e2)
1029 {
1030 if (debugEnabled())
1031 {
1032 TRACER.debugCaught(DebugLogLevel.ERROR, e2);
1033 }
1034 }
1035
1036 Message message = ERR_MONITOR_UNABLE_TO_EXPORT_BASE.get(
1037 stackTraceToSingleLineString(e));
1038 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
1039 message);
1040 }
1041
1042
1043 // Get all the monitor providers, convert them to entries, and write them to
1044 // LDIF.
1045 for (MonitorProvider monitorProvider :
1046 DirectoryServer.getMonitorProviders().values())
1047 {
1048 try
1049 {
1050 // TODO implementation of export is incomplete
1051 }
1052 catch (Exception e)
1053 {
1054 if (debugEnabled())
1055 {
1056 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1057 }
1058
1059 try
1060 {
1061 ldifWriter.close();
1062 }
1063 catch (Exception e2)
1064 {
1065 if (debugEnabled())
1066 {
1067 TRACER.debugCaught(DebugLogLevel.ERROR, e2);
1068 }
1069 }
1070
1071 Message message = ERR_MONITOR_UNABLE_TO_EXPORT_PROVIDER_ENTRY.
1072 get(monitorProvider.getMonitorInstanceName(),
1073 stackTraceToSingleLineString(e));
1074 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
1075 message);
1076 }
1077 }
1078
1079
1080 // Close the monitor provider and return.
1081 try
1082 {
1083 ldifWriter.close();
1084 }
1085 catch (Exception e)
1086 {
1087 if (debugEnabled())
1088 {
1089 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1090 }
1091 }
1092 }
1093
1094
1095
1096 /**
1097 * {@inheritDoc}
1098 */
1099 @Override()
1100 public boolean supportsLDIFImport()
1101 {
1102 // This backend does not support LDIF imports.
1103 return false;
1104 }
1105
1106
1107
1108 /**
1109 * {@inheritDoc}
1110 */
1111 @Override()
1112 public LDIFImportResult importLDIF(LDIFImportConfig importConfig)
1113 throws DirectoryException
1114 {
1115 // This backend does not support LDIF imports.
1116 Message message = ERR_MONITOR_IMPORT_NOT_SUPPORTED.get();
1117 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
1118 }
1119
1120
1121
1122 /**
1123 * {@inheritDoc}
1124 */
1125 @Override()
1126 public boolean supportsBackup()
1127 {
1128 // This backend does not provide a backup/restore mechanism.
1129 return false;
1130 }
1131
1132
1133
1134 /**
1135 * {@inheritDoc}
1136 */
1137 @Override()
1138 public boolean supportsBackup(BackupConfig backupConfig,
1139 StringBuilder unsupportedReason)
1140 {
1141 // This backend does not provide a backup/restore mechanism.
1142 return false;
1143 }
1144
1145
1146
1147 /**
1148 * {@inheritDoc}
1149 */
1150 @Override()
1151 public void createBackup(BackupConfig backupConfig)
1152 throws DirectoryException
1153 {
1154 // This backend does not provide a backup/restore mechanism.
1155 Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
1156 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
1157 }
1158
1159
1160
1161 /**
1162 * {@inheritDoc}
1163 */
1164 @Override()
1165 public void removeBackup(BackupDirectory backupDirectory,
1166 String backupID)
1167 throws DirectoryException
1168 {
1169 // This backend does not provide a backup/restore mechanism.
1170 Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
1171 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
1172 }
1173
1174
1175
1176 /**
1177 * {@inheritDoc}
1178 */
1179 @Override()
1180 public boolean supportsRestore()
1181 {
1182 // This backend does not provide a backup/restore mechanism.
1183 return false;
1184 }
1185
1186
1187
1188 /**
1189 * {@inheritDoc}
1190 */
1191 @Override()
1192 public void restoreBackup(RestoreConfig restoreConfig)
1193 throws DirectoryException
1194 {
1195 // This backend does not provide a backup/restore mechanism.
1196 Message message = ERR_MONITOR_BACKUP_AND_RESTORE_NOT_SUPPORTED.get();
1197 throw new DirectoryException(ResultCode.UNWILLING_TO_PERFORM, message);
1198 }
1199
1200
1201
1202 /**
1203 * {@inheritDoc}
1204 */
1205 public boolean isConfigurationChangeAcceptable(
1206 MonitorBackendCfg backendCfg,
1207 List<Message> unacceptableReasons)
1208 {
1209 // We'll pretty much accept anything here as long as it isn't one of our
1210 // private attributes.
1211 return true;
1212 }
1213
1214
1215
1216 /**
1217 * {@inheritDoc}
1218 */
1219 public ConfigChangeResult applyConfigurationChange(
1220 MonitorBackendCfg backendCfg)
1221 {
1222 ResultCode resultCode = ResultCode.SUCCESS;
1223 boolean adminActionRequired = false;
1224 ArrayList<Message> messages = new ArrayList<Message>();
1225
1226
1227 // Check to see if there is a new set of user-defined attributes.
1228 ArrayList<Attribute> userAttrs = new ArrayList<Attribute>();
1229 try
1230 {
1231 ConfigEntry configEntry = DirectoryServer.getConfigEntry(configEntryDN);
1232 for (List<Attribute> attrs :
1233 configEntry.getEntry().getUserAttributes().values())
1234 {
1235 for (Attribute a : attrs)
1236 {
1237 if (! isMonitorConfigAttribute(a))
1238 {
1239 userAttrs.add(a);
1240 }
1241 }
1242 }
1243 for (List<Attribute> attrs :
1244 configEntry.getEntry().getOperationalAttributes().values())
1245 {
1246 for (Attribute a : attrs)
1247 {
1248 if (! isMonitorConfigAttribute(a))
1249 {
1250 userAttrs.add(a);
1251 }
1252 }
1253 }
1254 }
1255 catch (Exception e)
1256 {
1257 if (debugEnabled())
1258 {
1259 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1260 }
1261
1262
1263 messages.add(ERR_CONFIG_BACKEND_ERROR_INTERACTING_WITH_BACKEND_ENTRY.get(
1264 String.valueOf(configEntryDN),
1265 stackTraceToSingleLineString(e)));
1266 resultCode = DirectoryServer.getServerErrorResultCode();
1267 }
1268
1269
1270 userDefinedAttributes = userAttrs;
1271
1272 Message message = INFO_MONITOR_USING_NEW_USER_ATTRS.get();
1273 messages.add(message);
1274
1275
1276 currentConfig = backendCfg;
1277 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
1278 }
1279
1280
1281
1282 /**
1283 * {@inheritDoc}
1284 */
1285 public void preloadEntryCache() throws UnsupportedOperationException {
1286 throw new UnsupportedOperationException("Operation not supported.");
1287 }
1288 }