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