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.extensions; 028 import org.opends.messages.Message; 029 030 import java.util.ArrayList; 031 import java.util.HashSet; 032 import java.util.LinkedHashSet; 033 import java.util.List; 034 import java.util.SortedSet; 035 036 import org.opends.server.core.DirectoryServer; 037 import org.opends.server.types.Attribute; 038 import org.opends.server.types.AttributeType; 039 import org.opends.server.types.AttributeValue; 040 import org.opends.server.types.DN; 041 import org.opends.server.types.DirectoryException; 042 import org.opends.server.types.ResultCode; 043 import org.opends.server.types.SearchFilter; 044 import org.opends.messages.MessageDescriptor; 045 046 import static org.opends.server.loggers.ErrorLogger.logError; 047 import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; 048 049 /** 050 * This class provides some common tools to all entry cache implementations. 051 */ 052 public class EntryCacheCommon 053 { 054 /** 055 * Configuration phases. Each value identifies a configuration step: 056 * - PHASE_INIT when invoking method initializeEntryCache() 057 * - PHASE_ACCEPTABLE when invoking method isConfigurationChangeAcceptable() 058 * - PHASE_APPLY when invoking method applyConfigurationChange() 059 */ 060 public static enum ConfigPhase 061 { 062 /** 063 * Indicates that entry cache is in initialization check phase. 064 */ 065 PHASE_INIT, 066 067 /** 068 * Indicates that entry cache is in configuration check phase. 069 */ 070 PHASE_ACCEPTABLE, 071 072 /** 073 * Indicates that entry cache is applying its configuration. 074 */ 075 PHASE_APPLY 076 } 077 078 /** 079 * Error handler used by local methods to report configuration error. 080 * The error handler simplifies the code of initializeEntryCache(), 081 * isConfigurationChangeAcceptable() and applyConfigurationChanges() methods. 082 */ 083 public class ConfigErrorHandler 084 { 085 // Configuration phase. 086 private EntryCacheCommon.ConfigPhase _configPhase; 087 088 // Unacceptable reasons. Used when _configPhase is PHASE_ACCEPTABLE. 089 private List<Message> _unacceptableReasons; 090 091 // Error messages. Used when _configPhase is PHASE_APPLY. 092 private ArrayList<Message> _errorMessages; 093 094 // Result code. Used when _configPhase is PHASE_APPLY. 095 private ResultCode _resultCode; 096 097 // Acceptable Configuration ? Used when _configPhase is PHASE_ACCEPTABLE 098 // or PHASE_APPLY. 099 private boolean _isAcceptable; 100 101 // Indicates whether administrative action is required or not. Used when 102 // _configPhase is PHASE_APPLY. 103 private boolean _isAdminActionRequired; 104 105 /** 106 * Create an error handler. 107 * 108 * @param configPhase the configuration phase for which the 109 * error handler is used 110 * @param unacceptableReasons the reasons why the configuration cannot 111 * be applied (during PHASE_ACCEPTABLE phase) 112 * @param errorMessages the errors found when applying a new 113 * configuration (during PHASE_APPLY phase) 114 */ 115 public ConfigErrorHandler ( 116 EntryCacheCommon.ConfigPhase configPhase, 117 List<Message> unacceptableReasons, 118 ArrayList<Message> errorMessages 119 ) 120 { 121 _configPhase = configPhase; 122 _unacceptableReasons = unacceptableReasons; 123 _errorMessages = errorMessages; 124 _resultCode = ResultCode.SUCCESS; 125 _isAcceptable = true; 126 _isAdminActionRequired = false; 127 } 128 129 /** 130 * Report an error. 131 * 132 * @param error the error to report 133 * @param isAcceptable <code>true</code> if the configuration is acceptable 134 * @param resultCode the change result for the current configuration 135 */ 136 public void reportError( 137 Message error, 138 boolean isAcceptable, 139 ResultCode resultCode 140 ) 141 { 142 switch (_configPhase) 143 { 144 case PHASE_INIT: 145 { 146 _errorMessages.add (error); 147 _isAcceptable = isAcceptable; 148 break; 149 } 150 case PHASE_ACCEPTABLE: 151 { 152 _unacceptableReasons.add (error); 153 _isAcceptable = isAcceptable; 154 break; 155 } 156 case PHASE_APPLY: 157 { 158 _errorMessages.add (error); 159 _isAcceptable = isAcceptable; 160 if (_resultCode == ResultCode.SUCCESS) 161 { 162 _resultCode = resultCode; 163 } 164 break; 165 } 166 } 167 } 168 169 /** 170 * Report an error. 171 * 172 * @param error the error to report 173 * @param isAcceptable <code>true</code> if the configuration is acceptable 174 * @param resultCode the change result for the current configuration 175 * @param isAdminActionRequired <code>true</code> if administrative action 176 * is required or <code>false</code> otherwise 177 */ 178 public void reportError( 179 Message error, 180 boolean isAcceptable, 181 ResultCode resultCode, 182 boolean isAdminActionRequired 183 ) 184 { 185 switch (_configPhase) 186 { 187 case PHASE_INIT: 188 { 189 logError (error); 190 break; 191 } 192 case PHASE_ACCEPTABLE: 193 { 194 _unacceptableReasons.add (error); 195 _isAcceptable = isAcceptable; 196 break; 197 } 198 case PHASE_APPLY: 199 { 200 _errorMessages.add (error); 201 _isAcceptable = isAcceptable; 202 if (_resultCode == ResultCode.SUCCESS) 203 { 204 _resultCode = resultCode; 205 } 206 _isAdminActionRequired = isAdminActionRequired; 207 break; 208 } 209 } 210 } 211 212 /** 213 * Get the current result code that was elaborated right after a 214 * configuration has been applied. 215 * 216 * @return the current result code 217 */ 218 public ResultCode getResultCode() 219 { 220 return _resultCode; 221 } 222 223 /** 224 * Get the current isAcceptable flag. The isAcceptable flag is elaborated 225 * right after the configuration was checked. 226 * 227 * @return the isAcceptable flag 228 */ 229 public boolean getIsAcceptable() 230 { 231 return _isAcceptable; 232 } 233 234 /** 235 * Get the current unacceptable reasons. The unacceptable reasons are 236 * elaborated when the configuration is checked. 237 * 238 * @return the list of unacceptable reasons 239 */ 240 public List<Message> getUnacceptableReasons() 241 { 242 return _unacceptableReasons; 243 } 244 245 /** 246 * Get the current error messages. The error messages are elaborated 247 * when the configuration is applied. 248 * 249 * @return the list of error messages 250 */ 251 public ArrayList<Message> getErrorMessages() 252 { 253 return _errorMessages; 254 } 255 256 /** 257 * Get the current configuration phase. The configuration phase indicates 258 * whether the entry cache is in initialization step, or in configuration 259 * checking step or in configuration being applied step. 260 * 261 * @return the current configuration phase. 262 */ 263 public ConfigPhase getConfigPhase() 264 { 265 return _configPhase; 266 } 267 268 /** 269 * Get the current isAdminActionRequired flag as determined after apply 270 * action has been taken on a given configuration. 271 * 272 * @return the isAdminActionRequired flag 273 */ 274 public boolean getIsAdminActionRequired() 275 { 276 return _isAdminActionRequired; 277 } 278 } // ConfigErrorHandler 279 280 281 /** 282 * Reads a list of string filters and convert it to a list of search 283 * filters. 284 * 285 * @param filters the list of string filter to convert to search filters 286 * @param decodeErrorMsg the error message ID to use in case of error 287 * @param errorHandler error handler to report filter decoding errors on 288 * @param configEntryDN the entry cache configuration DN 289 * 290 * @return the set of search filters 291 */ 292 public static HashSet<SearchFilter> getFilters ( 293 SortedSet<String> filters, 294 MessageDescriptor.Arg3<CharSequence, CharSequence, CharSequence> 295 decodeErrorMsg, 296 ConfigErrorHandler errorHandler, 297 DN configEntryDN 298 ) 299 { 300 // Returned value 301 HashSet<SearchFilter> searchFilters = new HashSet<SearchFilter>(); 302 303 // Convert the string filters to search filters. 304 if ((filters != null) && (! filters.isEmpty())) 305 { 306 for (String curFilter: filters) 307 { 308 try 309 { 310 searchFilters.add (SearchFilter.createFilterFromString (curFilter)); 311 } 312 catch (DirectoryException de) 313 { 314 // We couldn't decode this filter. Report an error and continue. 315 Message message = decodeErrorMsg.get(String.valueOf(configEntryDN), 316 curFilter, (de.getMessage() != null ? de.getMessage() : 317 stackTraceToSingleLineString(de))); 318 errorHandler.reportError(message, false, 319 ResultCode.INVALID_ATTRIBUTE_SYNTAX); 320 } 321 } 322 } 323 324 // done 325 return searchFilters; 326 } 327 328 329 /** 330 * Create a new error handler. 331 * 332 * @param configPhase the configuration phase for which the 333 * error handler is used 334 * @param unacceptableReasons the reasons why the configuration cannot 335 * be applied (during PHASE_ACCEPTABLE phase) 336 * @param errorMessages the errors found when applying a new 337 * configuration (during PHASE_APPLY phase) 338 * 339 * @return a new configuration error handler 340 */ 341 public static ConfigErrorHandler getConfigErrorHandler ( 342 EntryCacheCommon.ConfigPhase configPhase, 343 List<Message> unacceptableReasons, 344 ArrayList<Message> errorMessages 345 ) 346 { 347 ConfigErrorHandler errorHandler = null; 348 349 EntryCacheCommon ec = new EntryCacheCommon(); 350 351 errorHandler = ec.new ConfigErrorHandler ( 352 configPhase, unacceptableReasons, errorMessages 353 ); 354 return errorHandler; 355 } 356 357 358 /** 359 * Constructs a set of generic attributes containing entry cache 360 * monitor data. Note that <code>null</code> can be passed in 361 * place of any argument to denote the argument is omitted, such 362 * is when no state data of a given kind is available or can be 363 * provided. 364 * 365 * @param cacheHits number of cache hits. 366 * @param cacheMisses number of cache misses. 367 * @param cacheSize size of the current cache, in bytes. 368 * @param maxCacheSize maximum allowed cache size, in bytes. 369 * @param cacheCount number of entries stored in the cache. 370 * @param maxCacheCount maximum number of cache entries allowed. 371 * 372 * @return A set of generic attributes containing monitor data. 373 */ 374 public static ArrayList<Attribute> getGenericMonitorData( 375 Long cacheHits, 376 Long cacheMisses, 377 Long cacheSize, 378 Long maxCacheSize, 379 Long cacheCount, 380 Long maxCacheCount) 381 { 382 ArrayList<Attribute> attrs = new ArrayList<Attribute>(); 383 384 if (cacheHits != null) { 385 AttributeType hitsAttrType = 386 DirectoryServer.getDefaultAttributeType("entryCacheHits"); 387 LinkedHashSet<AttributeValue> hitsValues = 388 new LinkedHashSet<AttributeValue>(); 389 hitsValues.add(new AttributeValue(hitsAttrType, 390 cacheHits.toString())); 391 attrs.add(new Attribute(hitsAttrType, "entryCacheHits", 392 hitsValues)); 393 // Cache misses is required to get cache tries and hit ratio. 394 if (cacheMisses != null) { 395 AttributeType triesAttrType = 396 DirectoryServer.getDefaultAttributeType("entryCacheTries"); 397 LinkedHashSet<AttributeValue> triesValues = 398 new LinkedHashSet<AttributeValue>(); 399 Long cacheTries = cacheHits + cacheMisses; 400 triesValues.add(new AttributeValue(triesAttrType, 401 cacheTries.toString())); 402 attrs.add(new Attribute(triesAttrType, "entryCacheTries", 403 triesValues)); 404 405 AttributeType hitRatioAttrType = 406 DirectoryServer.getDefaultAttributeType("entryCacheHitRatio"); 407 LinkedHashSet<AttributeValue> hitRatioValues = 408 new LinkedHashSet<AttributeValue>(); 409 Double hitRatioRaw = cacheTries > 0 ? 410 cacheHits.doubleValue() / cacheTries.doubleValue() : 411 cacheHits.doubleValue() / 1; 412 Double hitRatio = hitRatioRaw * 100D; 413 hitRatioValues.add(new AttributeValue(hitRatioAttrType, 414 Long.toString(hitRatio.longValue()))); 415 attrs.add(new Attribute(hitRatioAttrType, "entryCacheHitRatio", 416 hitRatioValues)); 417 } 418 } 419 420 if (cacheSize != null) { 421 AttributeType memoryAttrType = 422 DirectoryServer.getDefaultAttributeType("currentEntryCacheSize"); 423 LinkedHashSet<AttributeValue> memoryValues = 424 new LinkedHashSet<AttributeValue>(); 425 memoryValues.add(new AttributeValue(memoryAttrType, 426 cacheSize.toString())); 427 attrs.add(new Attribute(memoryAttrType, "currentEntryCacheSize", 428 memoryValues)); 429 } 430 431 if (maxCacheSize != null) { 432 AttributeType maxMemoryAttrType = 433 DirectoryServer.getDefaultAttributeType("maxEntryCacheSize"); 434 LinkedHashSet<AttributeValue> maxMemoryValues = 435 new LinkedHashSet<AttributeValue>(); 436 maxMemoryValues.add(new AttributeValue(maxMemoryAttrType, 437 maxCacheSize.toString())); 438 attrs.add(new Attribute(maxMemoryAttrType, "maxEntryCacheSize", 439 maxMemoryValues)); 440 } 441 442 if (cacheCount != null) { 443 AttributeType entriesAttrType = 444 DirectoryServer.getDefaultAttributeType("currentEntryCacheCount"); 445 LinkedHashSet<AttributeValue> entriesValues = 446 new LinkedHashSet<AttributeValue>(); 447 entriesValues.add(new AttributeValue(entriesAttrType, 448 cacheCount.toString())); 449 attrs.add(new Attribute(entriesAttrType, "currentEntryCacheCount", 450 entriesValues)); 451 } 452 453 if (maxCacheCount != null) { 454 AttributeType maxEntriesAttrType = 455 DirectoryServer.getDefaultAttributeType("maxEntryCacheCount"); 456 LinkedHashSet<AttributeValue> maxEntriesValues = 457 new LinkedHashSet<AttributeValue>(); 458 maxEntriesValues.add(new AttributeValue(maxEntriesAttrType, 459 maxCacheCount.toString())); 460 attrs.add(new Attribute(maxEntriesAttrType, "maxEntryCacheCount", 461 maxEntriesValues)); 462 } 463 464 return attrs; 465 } 466 467 } 468