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