001package com.pingidentity.ds.plugin; 002 003import com.unboundid.directory.sdk.common.api.MonitorProvider; 004import com.unboundid.directory.sdk.common.operation.*; 005import com.unboundid.directory.sdk.common.types.ActiveOperationContext; 006import com.unboundid.directory.sdk.common.types.ActiveSearchOperationContext; 007import com.unboundid.directory.sdk.common.types.RegisteredMonitorProvider; 008import com.unboundid.directory.sdk.ds.api.Plugin; 009import com.unboundid.directory.sdk.ds.config.PluginConfig; 010import com.unboundid.directory.sdk.ds.types.DirectoryServerContext; 011import com.unboundid.directory.sdk.ds.types.PreParsePluginResult; 012import com.unboundid.ldap.sdk.Attribute; 013import com.unboundid.ldap.sdk.Control; 014import com.unboundid.ldap.sdk.LDAPException; 015import com.unboundid.ldap.sdk.ResultCode; 016import com.unboundid.ldap.sdk.controls.*; 017import com.unboundid.ldap.sdk.unboundidds.controls.*; 018import com.unboundid.util.StaticUtils; 019import com.unboundid.util.args.ArgumentException; 020import com.unboundid.util.args.ArgumentParser; 021import com.unboundid.util.args.StringArgument; 022 023import java.util.*; 024import java.util.concurrent.atomic.AtomicLong; 025 026/** 027 * This class provides 028 */ 029public class ControlsInjector extends Plugin { 030 private static final String CONTROL_ADMINISTRATIVE_OPERATION = "AdministrativeOperation"; 031 private static final String CONTROL_DONT_USE_COPY = "DontUseCopy"; 032 private static final String CONTROL_EXTENDED_SCHEMA_INFO = "ExtendedSchemaInfo"; 033 private static final String CONTROL_HARD_DELETE = "HardDelete"; 034 private static final String CONTROL_IGNORE_NO_USER_MODIFICATION = "IgnoreNoUserModification"; 035 private static final String CONTROL_MANAGE_DSA_IT = "ManageDsaIT"; 036 private static final String CONTROL_NAME_WITH_ENTRYUUD = "NameWithEntryUUID"; 037 private static final String CONTROL_NOOP = "NoOp"; 038 private static final String CONTROL_PERMISSIVE_MODIFY = "PermissiveModify"; 039 private static final String CONTROL_REAL_ATTRIBUTES_ONLY = "RealAttributesOnly"; 040 private static final String CONTROL_REPLICATION_REPAIR = "ReplicationRepair"; 041 private static final String CONTROL_RETAIN_IDENTITY = "RetainIdentity"; 042 private static final String CONTROL_RETURN_CONFLICT_ENTRIES = "ReturnConflictEntries"; 043 private static final String CONTROL_SUBENTRIES = "Subentries"; 044 private final static String CONTROL_SUBTREE_DELETE = "SubtreeDelete"; 045 private final static String CONTROL_SUPPRESS_REFERENTIAL_INTEGRITY_UPDATES = "SuppressReferentialIntegrityUpdates"; 046 private final static String CONTROL_UNDELETE = "Undelete"; 047 private final static String CONTROL_VIRTUAL_ATTRIBUTES_ONLY = "VirtualAttributesOnly"; 048 049 private final static String OP_ABANDON = "abandon"; 050 private final static String OP_ADD = "add"; 051 private final static String OP_BIND_SIMPLE = "simple-bind"; 052 private final static String OP_BIND_SASL = "sasl-bind"; 053 private final static String OP_COMPARE = "compare"; 054 private final static String OP_DELETE = "delete"; 055 private final static String OP_EXTENDED = "extended"; 056 private final static String OP_MODIFY = "modify"; 057 private final static String OP_MODIFY_DN = "moddn"; 058 private final static String OP_SEARCH = "search"; 059 private final static String OP_UNBIND = "unbind"; 060 private final static String[] OPERATIONS = new String[]{ 061 OP_ABANDON, 062 OP_ADD, 063 OP_BIND_SIMPLE, 064 OP_BIND_SASL, 065 OP_COMPARE, 066 OP_EXTENDED, 067 OP_MODIFY, 068 OP_MODIFY_DN, 069 OP_SEARCH, 070 OP_UNBIND 071 }; 072 073 074 private static final String[] SUPPORTED_REQUEST_CONTROLS = new String[]{ 075 CONTROL_ADMINISTRATIVE_OPERATION, 076 CONTROL_DONT_USE_COPY, 077 CONTROL_EXTENDED_SCHEMA_INFO, 078 CONTROL_HARD_DELETE, 079 CONTROL_IGNORE_NO_USER_MODIFICATION, 080 CONTROL_MANAGE_DSA_IT, 081 CONTROL_NAME_WITH_ENTRYUUD, 082 CONTROL_NOOP, 083 CONTROL_PERMISSIVE_MODIFY, 084 CONTROL_REAL_ATTRIBUTES_ONLY, 085 CONTROL_REPLICATION_REPAIR, 086 CONTROL_RETAIN_IDENTITY, 087 CONTROL_RETURN_CONFLICT_ENTRIES, 088 CONTROL_SUBENTRIES, 089 CONTROL_SUBTREE_DELETE, 090 CONTROL_SUPPRESS_REFERENTIAL_INTEGRITY_UPDATES, 091 CONTROL_UNDELETE, 092 CONTROL_VIRTUAL_ATTRIBUTES_ONLY 093 }; 094 private static final HashSet<String> SUPPORTED_REQUEST_CONTROLS_SET = new HashSet<>(Arrays.asList 095 (SUPPORTED_REQUEST_CONTROLS)); 096 097 private static final String ARG_REQUEST_CONTROL_NAME = "request-control"; 098 private Control additionalRequestControl; 099 private HashMap<String,AtomicLong> counters = new HashMap<>(11); 100 private PluginConfig config; 101 private DirectoryServerContext serverContext; 102 103 private RegisteredMonitorProvider registeredMonitorProvider; 104 105 private String join(String separator, String[] array) { 106 if (array == null) { 107 return null; 108 } 109 if (separator == null) { 110 separator = ""; 111 } 112 StringBuilder result = new StringBuilder(); 113 for (String element : array) { 114 result.append(result.length() > 0 ? separator + element : element); 115 } 116 return result.toString(); 117 } 118 119 @Override 120 public String getExtensionName() { 121 return "Controls Injector"; 122 } 123 124 @Override 125 public String[] getExtensionDescription() { 126 return new String[]{"An extension that allows to inject controls to incoming requests.", 127 "Supported controls and their OIDs:" + 128 "<ul>\n" + 129 "<li>AdministrativeOperation (1.3.6.1.4.1.30221.2.5.11)</li>\n" + 130 "<li>DontUseCopy (1.3.6.1.1.22)</li>\n" + 131 "<li>ExtendedSchemaInfo (1.3.6.1.4.1.30221.2.5.12)</li>\n" + 132 "<li>HardDelete (1.3.6.1.4.1.30221.2.5.22)</li>\n" + 133 "<li>IgnoreNoUserModification (1.3.6.1.4.1.30221.2.5.5)</li>\n" + 134 "<li>ManageDsaIT (2.16.840.1.113730.3.4.2)</li>\n" + 135 "<li>NameWithEntryUUID (1.3.6.1.4.1.30221.2.5.44)</li>\n" + 136 "<li>NoOp (1.3.6.1.4.1.4203.1.10.2)</li>\n" + 137 "<li>PermissiveModify (1.2.840.113556.1.4.1413)</li>\n" + 138 "<li>RealAttributesOnly (2.16.840.1.113730.3.4.17)</li>\n" + 139 "<li>ReplicationRepair (1.3.6.1.4.1.30221.1.5.2)</li>\n" + 140 "<li>RetainIdentity (1.3.6.1.4.1.30221.2.5.3)</li>\n" + 141 "<li>ReturnConflictEntries (1.3.6.1.4.1.30221.2.5.13)</li>\n" + 142 "<li>Subentries (1.3.6.1.4.1.7628.5.101.1)</li>\n" + 143 "<li>SubtreeDelete (1.2.840.113556.1.4.805)</li>\n" + 144 "<li>SuppressReferentialIntegrityUpdates (1.3.6.1.4.1.30221.2.5.30)</li>\n" + 145 "<li>Undelete (1.3.6.1.4.1.30221.2.5.23)</li>\n" + 146 "<li>VirtualAttributesOnly (2.16.840.1.113730.3.4.19)</li>\n" + 147 "</ul>\n", 148 "The list above is provided because you may have to add ACI rules to allow for the control to be used. For example:" + 149 "<pre>\n" + 150 "(targetcontrol=\"1.3.6.1.4.1.4203.1.10.2\")(version 3.0; acl \"allow use of NoOp control on own entry\"; allow(read) userdn=\"ldap:///self\";)" + 151 "</pre>\n", 152 "To create a plugin:\n" + 153 "<pre>\n" + 154 "dsconfig create-plugin \n" + 155 " --plugin-name noop-injector \n" + 156 " --type third-party \n" + 157 " --set enabled:false \n" + 158 " --set plugin-type:preparseabandon \n" + 159 " --set plugin-type:preparseadd \n" + 160 " --set plugin-type:preparsebind \n" + 161 " --set plugin-type:preparsecompare \n" + 162 " --set plugin-type:preparsedelete \n" + 163 " --set plugin-type:preparseextended \n" + 164 " --set plugin-type:preparsemodify \n" + 165 " --set plugin-type:preparsemodifydn \n" + 166 " --set plugin-type:preparsesearch \n" + 167 " --set plugin-type:preparseunbind \n" + 168 " --set extension-class:com.pingidentity.ds.plugin.ControlsInjector \n" + 169 " --set extension-argument:request-control=NoOp \n" + 170 " --set request-criteria:the-request-criteria-name" + 171 "</pre>", 172 "To retrieve monitoring information, search cn=monitor like:\n" + 173 "<pre>\n" + 174 "ldapsearch -b cn=monitor '(objectClass=ds-monitor-controls-injector)'\n" + 175 "dn: cn=noop-injector-monitor [from ThirdPartyPlugin:noop-injector],cn=monitor\n" + 176 "objectClass: top\n" + 177 "objectClass: ds-monitor-entry\n" + 178 "objectClass: ds-monitor-controls-injector\n" + 179 "objectClass: extensibleObject\n" + 180 "cn: noop-injector-monitor [from ThirdPartyPlugin:noop-injector]\n" + 181 "ds-extension-monitor-name: noop-injector-monitor\n" + 182 "ds-extension-type: ThirdPartyPlugin\n" + 183 "ds-extension-name: noop-injector\n" + 184 "processed-add: 0\n" + 185 "processed-modify: 0\n" + 186 "processed-compare: 0\n" + 187 "processed-search: 0\n" + 188 "processed-sasl-bind: 0\n" + 189 "processed-abandon: 0\n" + 190 "processed-unbind: 0\n" + 191 "processed-simple-bind: 0\n" + 192 "processed-extended: 0\n" + 193 "processed-moddn: 0" + 194 "</pre>", 195 "This example plugin would inject the NoOp control, as illustrated below:\n" + 196 "<pre>\n" + 197 "ldapmodify\n" + 198 "dn: uid=user.7,ou=People,dc=example,dc=com\n" + 199 "changetype: modify\n" + 200 "replace: description\n" + 201 "description: controls injector test 4\n" + 202 "\n" + 203 "# Modifying entry uid=user.7,ou=People,dc=example,dc=com ...\n" + 204 "# Result Code: 16654 (no operation)\n" + 205 "# Diagnostic Message: The modify operation was not actually performed in the Directory Server backend because the LDAP no-op control was present in the request" + 206 "</pre>", 207 "NOTE: you probably should never use this plugin without a request criteria." 208 }; 209 } 210 211 @Override 212 public void defineConfigArguments(ArgumentParser parser) throws ArgumentException { 213 parser.addArgument(new StringArgument(null, ARG_REQUEST_CONTROL_NAME, true, 1, "{control}", 214 "The name of a supported request control. Currently supported controls list: <br/>\n" 215 + "<ul><li>" 216 + join("</li>\n<li>", SUPPORTED_REQUEST_CONTROLS), SUPPORTED_REQUEST_CONTROLS_SET 217 + "</li></ul>")); 218 } 219 220 @Override 221 public void initializePlugin(DirectoryServerContext serverContext, PluginConfig config, ArgumentParser parser) 222 throws LDAPException { 223 this.config = config; 224 225 // Use the applyConfiguration method to set up the plugin. 226 final ArrayList<String> adminActionsRequired = new ArrayList<>(5); 227 final ArrayList<String> messages = new ArrayList<>(5); 228 final ResultCode resultCode = applyConfiguration(config, parser, adminActionsRequired, messages); 229 if (resultCode != ResultCode.SUCCESS) { 230 throw new LDAPException(resultCode, 231 "One or more errors occurred while trying to initialize " + getExtensionName() + " extension in '" 232 + config.getConfigObjectDN() + ": " + 233 StaticUtils.concatenateStrings(messages)); 234 } 235 for (String operation: OPERATIONS ) 236 counters.put(operation,new AtomicLong(0)); 237 registeredMonitorProvider = serverContext.registerMonitorProvider(new ControlsInjectorMonitorProvider(), config); 238 this.serverContext = serverContext; 239 } 240 241 @Override 242 public void finalizePlugin() { 243 if ( registeredMonitorProvider != null) 244 serverContext.deregisterMonitorProvider(registeredMonitorProvider); 245 } 246 247 @Override 248 public ResultCode applyConfiguration(PluginConfig config, ArgumentParser parser, List<String> 249 adminActionsRequired, List<String> messages) { 250 String selectedRequestControl = parser.getStringArgument(ARG_REQUEST_CONTROL_NAME).getValue(); 251 additionalRequestControl = null; 252 if (CONTROL_ADMINISTRATIVE_OPERATION.equalsIgnoreCase(selectedRequestControl)) { 253 additionalRequestControl = new AdministrativeOperationRequestControl(); 254 } 255 if (CONTROL_DONT_USE_COPY.equalsIgnoreCase(selectedRequestControl)) { 256 additionalRequestControl = new DontUseCopyRequestControl(); 257 } 258 if (CONTROL_EXTENDED_SCHEMA_INFO.equalsIgnoreCase(selectedRequestControl)) { 259 additionalRequestControl = new ExtendedSchemaInfoRequestControl(); 260 } 261 if (CONTROL_HARD_DELETE.equalsIgnoreCase(selectedRequestControl)) { 262 additionalRequestControl = new HardDeleteRequestControl(); 263 } 264 if (CONTROL_IGNORE_NO_USER_MODIFICATION.equalsIgnoreCase(selectedRequestControl)) { 265 additionalRequestControl = new IgnoreNoUserModificationRequestControl(); 266 } 267 if (CONTROL_MANAGE_DSA_IT.equalsIgnoreCase(selectedRequestControl)) { 268 additionalRequestControl = new ManageDsaITRequestControl(); 269 } 270 if (CONTROL_NAME_WITH_ENTRYUUD.equalsIgnoreCase(selectedRequestControl)) { 271 additionalRequestControl = new NameWithEntryUUIDRequestControl(); 272 } 273 if (CONTROL_NOOP.equalsIgnoreCase(selectedRequestControl)) { 274 additionalRequestControl = new NoOpRequestControl(); 275 } 276 if (CONTROL_PERMISSIVE_MODIFY.equalsIgnoreCase(selectedRequestControl)) { 277 additionalRequestControl = new PermissiveModifyRequestControl(); 278 } 279 if (CONTROL_REAL_ATTRIBUTES_ONLY.equalsIgnoreCase(selectedRequestControl)) { 280 additionalRequestControl = new RealAttributesOnlyRequestControl(); 281 } 282 if (CONTROL_REPLICATION_REPAIR.equalsIgnoreCase(selectedRequestControl)) { 283 additionalRequestControl = new ReplicationRepairRequestControl(); 284 } 285 if (CONTROL_RETAIN_IDENTITY.equalsIgnoreCase(selectedRequestControl)) { 286 additionalRequestControl = new RetainIdentityRequestControl(); 287 } 288 if (CONTROL_RETURN_CONFLICT_ENTRIES.equalsIgnoreCase(selectedRequestControl)) { 289 additionalRequestControl = new ReturnConflictEntriesRequestControl(); 290 } 291 if (CONTROL_SUBENTRIES.equalsIgnoreCase(selectedRequestControl)) { 292 additionalRequestControl = new SubentriesRequestControl(); 293 } 294 if (CONTROL_SUBTREE_DELETE.equalsIgnoreCase(selectedRequestControl)) { 295 additionalRequestControl = new SubtreeDeleteRequestControl(); 296 } 297 if (CONTROL_SUPPRESS_REFERENTIAL_INTEGRITY_UPDATES.equalsIgnoreCase(selectedRequestControl)) { 298 additionalRequestControl = new SuppressReferentialIntegrityUpdatesRequestControl(); 299 } 300 if (CONTROL_UNDELETE.equalsIgnoreCase(selectedRequestControl)) { 301 additionalRequestControl = new UndeleteRequestControl(); 302 } 303 if ( CONTROL_VIRTUAL_ATTRIBUTES_ONLY.equalsIgnoreCase(selectedRequestControl)) { 304 additionalRequestControl = new VirtualAttributesOnlyRequestControl(); 305 } 306 return ResultCode.SUCCESS; 307 } 308 309 /** 310 * Performs the necessary processing to add the configured control to ABANDON requests 311 * 312 * @param operationContext the operation context 313 * @param request the request to update 314 * @return PreParsePluginResult.SUCCESS 315 */ 316 @Override 317 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableAbandonRequest request) { 318 counters.get(OP_ABANDON).incrementAndGet(); 319 processUpdatableRequest(request); 320 return PreParsePluginResult.SUCCESS; 321 } 322 323 /** 324 * Performs the necessary processing to add the configured control to ADD requests 325 * 326 * @param operationContext the operation context 327 * @param request the request to update 328 * @param result the updatable result 329 * @return PreParsePluginResult.SUCCESS 330 */ 331 @Override 332 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableAddRequest request, 333 UpdatableAddResult result) { 334 counters.get(OP_ADD).incrementAndGet(); 335 processUpdatableRequest(request); 336 return PreParsePluginResult.SUCCESS; 337 } 338 339 /** 340 * Performs the necessary processing to add the configured control to Simple BIND requests 341 * 342 * @param operationContext the operation context 343 * @param request the request to update 344 * @param result the updatable result 345 * @return PreParsePluginResult.SUCCESS 346 */ 347 @Override 348 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableSimpleBindRequest 349 request, UpdatableBindResult result) { 350 counters.get(OP_BIND_SIMPLE).incrementAndGet(); 351 processUpdatableRequest(request); 352 return PreParsePluginResult.SUCCESS; 353 } 354 355 /** 356 * Performs the necessary processing to add the configured control to SASL BIND requests 357 * 358 * @param operationContext the operation context 359 * @param request the request to update 360 * @param result the updatable result 361 * @return PreParsePluginResult.SUCCESS 362 */ 363 @Override 364 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableSASLBindRequest request, 365 UpdatableBindResult result) { 366 counters.get(OP_BIND_SASL).incrementAndGet(); 367 processUpdatableRequest(request); 368 return PreParsePluginResult.SUCCESS; 369 } 370 371 /** 372 * Performs the necessary processing to add the configured control to COMPARE requests 373 * 374 * @param operationContext the operation context 375 * @param request the request to update 376 * @param result the updatable result 377 * @return PreParsePluginResult.SUCCESS 378 */ 379 @Override 380 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableCompareRequest request, 381 UpdatableCompareResult result) { 382 counters.get(OP_COMPARE).incrementAndGet(); 383 processUpdatableRequest(request); 384 return PreParsePluginResult.SUCCESS; 385 } 386 387 /** 388 * Performs the necessary processing to add the configured control to DELETE requests 389 * 390 * @param operationContext the operation context 391 * @param request the request to update 392 * @param result the updatable result 393 * @return PreParsePluginResult.SUCCESS 394 */ 395 @Override 396 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableDeleteRequest request, 397 UpdatableDeleteResult result) { 398 counters.get(OP_DELETE).incrementAndGet(); 399 processUpdatableRequest(request); 400 return PreParsePluginResult.SUCCESS; 401 } 402 403 /** 404 * Performs the necessary processing to add the configured control to EXTENDED requests 405 * 406 * @param operationContext the operation context 407 * @param request the request to update 408 * @param result the updatable result 409 * @return PreParsePluginResult.SUCCESS 410 */ 411 @Override 412 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableExtendedRequest request, 413 UpdatableExtendedResult result) { 414 counters.get(OP_EXTENDED).incrementAndGet(); 415 processUpdatableRequest(request); 416 return PreParsePluginResult.SUCCESS; 417 } 418 419 /** 420 * Performs the necessary processing to add the configured control to MODIFY requests 421 * 422 * @param operationContext the operation context 423 * @param request the request to update 424 * @param result the updatable result 425 * @return PreParsePluginResult.SUCCESS 426 */ 427 @Override 428 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableModifyRequest request, 429 UpdatableModifyResult result) { 430 counters.get(OP_MODIFY).incrementAndGet(); 431 processUpdatableRequest(request); 432 return PreParsePluginResult.SUCCESS; 433 } 434 435 /** 436 * Performs the necessary processing to add the configured control to MODIFY DN requests 437 * 438 * @param operationContext the operation context 439 * @param request the request to update 440 * @param result the updatable result 441 * @return PreParsePluginResult.SUCCESS 442 */ 443 @Override 444 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableModifyDNRequest request, 445 UpdatableModifyDNResult result) { 446 counters.get(OP_MODIFY_DN).incrementAndGet(); 447 processUpdatableRequest(request); 448 return PreParsePluginResult.SUCCESS; 449 } 450 451 /** 452 * Performs the necessary processing to add the configured control to SEARCH requests 453 * 454 * @param operationContext the operation context 455 * @param request the request to update 456 * @param result the updatable result 457 * @return PreParsePluginResult.SUCCESS 458 */ 459 @Override 460 public PreParsePluginResult doPreParse(ActiveSearchOperationContext operationContext, UpdatableSearchRequest 461 request, UpdatableSearchResult result) { 462 counters.get(OP_SEARCH).incrementAndGet(); 463 processUpdatableRequest(request); 464 return PreParsePluginResult.SUCCESS; 465 } 466 467 /** 468 * Performs the necessary processing to add the configured control to UNBIND requests 469 * 470 * @param operationContext the operation context 471 * @param request the request to update 472 * @return PreParsePluginResult.SUCCESS 473 */ 474 @Override 475 public PreParsePluginResult doPreParse(ActiveOperationContext operationContext, UpdatableUnbindRequest request) { 476 counters.get(OP_UNBIND).incrementAndGet(); 477 processUpdatableRequest(request); 478 return PreParsePluginResult.SUCCESS; 479 } 480 481 /** 482 * Convenience method to stay DRY in each operation-specific method 483 * 484 * @param request the updatable request to add controls to 485 */ 486 private void processUpdatableRequest(UpdatableRequest request) { 487 if (additionalRequestControl != null) { 488 request.setRequestControls(addRequestControl(request.getRequestControls(), additionalRequestControl)); 489 } 490 } 491 492 /** 493 * Convenience method to add a control to a list of controls 494 * If the additional control has the same OID as another control already in the list 495 * the additional control will override the control already in the list 496 * 497 * @param requestControls the list of controls to add a control to 498 * @param additionalControl the additional control to add to the list 499 * @return the list of controls with the additional control 500 */ 501 List<Control> addRequestControl(List<Control> requestControls, Control additionalControl) { 502 List<Control> result = new ArrayList<>(); 503 if (requestControls != null) { 504 for (Control control : requestControls) { 505 // this test effectively results in additionalControl overriding any control in the list with that OID 506 if (!control.getOID().equals(additionalControl.getOID())) 507 result.add(control); 508 } 509 } 510 result.add(additionalControl); 511 return result; 512 } 513 514 public class ControlsInjectorMonitorProvider extends MonitorProvider { 515 public ControlsInjectorMonitorProvider() { 516 } 517 518 @Override 519 public String getMonitorObjectClass() { 520 return "ds-monitor-controls-injector"; 521 } 522 523 @Override 524 public String getExtensionName() { 525 return "ControlsInjectorMonitorProvider"; 526 } 527 528 @Override 529 public String[] getExtensionDescription() { 530 return null; 531 } 532 533 @Override 534 public String getMonitorInstanceName() { 535 return config.getConfigObjectName()+"-monitor"; 536 } 537 538 @Override 539 public List<Attribute> getMonitorAttributes() { 540 List<Attribute> result = new ArrayList<>(11); 541 for (String key: counters.keySet() ) 542 result.add(new Attribute("processed-"+key,String.valueOf(counters.get(key).get()))); 543 return result; 544 } 545 } 546}