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