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.core;
028 import org.opends.messages.Message;
029
030
031
032 import java.lang.reflect.Method;
033 import java.util.ArrayList;
034 import java.util.Iterator;
035 import java.util.List;
036 import java.util.concurrent.ConcurrentHashMap;
037
038 import org.opends.server.admin.ClassPropertyDefinition;
039 import org.opends.server.admin.server.ConfigurationAddListener;
040 import org.opends.server.admin.server.ConfigurationChangeListener;
041 import org.opends.server.admin.server.ConfigurationDeleteListener;
042 import org.opends.server.admin.std.meta.AlertHandlerCfgDefn;
043 import org.opends.server.admin.std.server.AlertHandlerCfg;
044 import org.opends.server.admin.std.server.RootCfg;
045 import org.opends.server.admin.server.ServerManagementContext;
046 import org.opends.server.api.AlertHandler;
047 import org.opends.server.config.ConfigException;
048 import org.opends.server.types.ConfigChangeResult;
049 import org.opends.server.types.DN;
050
051
052 import org.opends.server.types.InitializationException;
053 import org.opends.server.types.ResultCode;
054
055 import static org.opends.messages.ConfigMessages.*;
056
057 import static org.opends.server.util.StaticUtils.*;
058 import org.opends.server.loggers.ErrorLogger;
059
060
061 /**
062 * This class defines a utility that will be used to manage the set of alert
063 * handlers defined in the Directory Server. It will initialize the alert
064 * handlers when the server starts, and then will manage any additions,
065 * removals, or modifications to any alert handlers while the server is running.
066 */
067 public class AlertHandlerConfigManager
068 implements ConfigurationChangeListener<AlertHandlerCfg>,
069 ConfigurationAddListener<AlertHandlerCfg>,
070 ConfigurationDeleteListener<AlertHandlerCfg>
071
072 {
073 // A mapping between the DNs of the config entries and the associated alert
074 // handlers.
075 private ConcurrentHashMap<DN,AlertHandler> alertHandlers;
076
077
078
079 /**
080 * Creates a new instance of this alert handler config manager.
081 */
082 public AlertHandlerConfigManager()
083 {
084 alertHandlers = new ConcurrentHashMap<DN,AlertHandler>();
085 }
086
087
088
089 /**
090 * Initializes all alert handlers currently defined in the Directory Server
091 * configuration. This should only be called at Directory Server startup.
092 *
093 * @throws ConfigException If a configuration problem causes the alert
094 * handler initialization process to fail.
095 *
096 * @throws InitializationException If a problem occurs while initializing
097 * the alert handlers that is not related to
098 * the server configuration.
099 */
100 public void initializeAlertHandlers()
101 throws ConfigException, InitializationException
102 {
103 // Get the root configuration object.
104 ServerManagementContext managementContext =
105 ServerManagementContext.getInstance();
106 RootCfg rootConfiguration = managementContext.getRootConfiguration();
107
108
109 // Register as an add and delete listener with the root configuration so we
110 // can be notified if any alert handler entries are added or removed.
111 rootConfiguration.addAlertHandlerAddListener(this);
112 rootConfiguration.addAlertHandlerDeleteListener(this);
113
114
115 //Initialize the existing alert handlers.
116 for (String name : rootConfiguration.listAlertHandlers())
117 {
118 AlertHandlerCfg configuration = rootConfiguration.getAlertHandler(name);
119 configuration.addChangeListener(this);
120
121 if (configuration.isEnabled())
122 {
123 String className = configuration.getJavaClass();
124 try
125 {
126 AlertHandler handler = loadHandler(className, configuration, true);
127 alertHandlers.put(configuration.dn(), handler);
128 DirectoryServer.registerAlertHandler(handler);
129 }
130 catch (InitializationException ie)
131 {
132 ErrorLogger.logError(ie.getMessageObject());
133 continue;
134 }
135 }
136 }
137 }
138
139
140
141 /**
142 * {@inheritDoc}
143 */
144 public boolean isConfigurationAddAcceptable(AlertHandlerCfg configuration,
145 List<Message> unacceptableReasons)
146 {
147 if (configuration.isEnabled())
148 {
149 // Get the name of the class and make sure we can instantiate it as an
150 // alert handler.
151 String className = configuration.getJavaClass();
152 try
153 {
154 loadHandler(className, configuration, false);
155 }
156 catch (InitializationException ie)
157 {
158 unacceptableReasons.add(ie.getMessageObject());
159 return false;
160 }
161 }
162
163 // If we've gotten here, then it's fine.
164 return true;
165 }
166
167
168
169 /**
170 * {@inheritDoc}
171 */
172 public ConfigChangeResult applyConfigurationAdd(AlertHandlerCfg configuration)
173 {
174 ResultCode resultCode = ResultCode.SUCCESS;
175 boolean adminActionRequired = false;
176 ArrayList<Message> messages = new ArrayList<Message>();
177
178 configuration.addChangeListener(this);
179
180 if (! configuration.isEnabled())
181 {
182 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
183 }
184
185 AlertHandler alertHandler = null;
186
187 // Get the name of the class and make sure we can instantiate it as an alert
188 // handler.
189 String className = configuration.getJavaClass();
190 try
191 {
192 alertHandler = loadHandler(className, configuration, true);
193 }
194 catch (InitializationException ie)
195 {
196 if (resultCode == ResultCode.SUCCESS)
197 {
198 resultCode = DirectoryServer.getServerErrorResultCode();
199 }
200
201 messages.add(ie.getMessageObject());
202 }
203
204 if (resultCode == ResultCode.SUCCESS)
205 {
206 alertHandlers.put(configuration.dn(), alertHandler);
207 DirectoryServer.registerAlertHandler(alertHandler);
208 }
209
210 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
211 }
212
213
214
215 /**
216 * {@inheritDoc}
217 */
218 public boolean isConfigurationDeleteAcceptable(
219 AlertHandlerCfg configuration,
220 List<Message> unacceptableReasons)
221 {
222 // FIXME -- We should try to perform some check to determine whether the
223 // alert handler is in use.
224 return true;
225 }
226
227
228
229 /**
230 * {@inheritDoc}
231 */
232 public ConfigChangeResult applyConfigurationDelete(
233 AlertHandlerCfg configuration)
234 {
235 ResultCode resultCode = ResultCode.SUCCESS;
236 boolean adminActionRequired = false;
237 ArrayList<Message> messages = new ArrayList<Message>();
238
239 AlertHandler alertHandler = alertHandlers.remove(configuration.dn());
240 if (alertHandler != null)
241 {
242 DirectoryServer.deregisterAlertHandler(alertHandler);
243 alertHandler.finalizeAlertHandler();
244 }
245
246 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
247 }
248
249
250
251 /**
252 * {@inheritDoc}
253 */
254 public boolean isConfigurationChangeAcceptable(AlertHandlerCfg configuration,
255 List<Message> unacceptableReasons)
256 {
257 if (configuration.isEnabled())
258 {
259 // Get the name of the class and make sure we can instantiate it as an
260 // alert handler.
261 String className = configuration.getJavaClass();
262 try
263 {
264 loadHandler(className, configuration, false);
265 }
266 catch (InitializationException ie)
267 {
268 unacceptableReasons.add(ie.getMessageObject());
269 return false;
270 }
271 }
272
273 // If we've gotten here, then it's fine.
274 return true;
275 }
276
277
278
279 /**
280 * {@inheritDoc}
281 */
282 public ConfigChangeResult applyConfigurationChange(
283 AlertHandlerCfg configuration)
284 {
285 ResultCode resultCode = ResultCode.SUCCESS;
286 boolean adminActionRequired = false;
287 ArrayList<Message> messages = new ArrayList<Message>();
288
289
290 // Get the existing alert handler if it's already enabled.
291 AlertHandler existingHandler = alertHandlers.get(configuration.dn());
292
293
294 // If the new configuration has the handler disabled, then disable it if it
295 // is enabled, or do nothing if it's already disabled.
296 if (! configuration.isEnabled())
297 {
298 if (existingHandler != null)
299 {
300 DirectoryServer.deregisterAlertHandler(existingHandler);
301
302 AlertHandler alertHandler = alertHandlers.remove(configuration.dn());
303 if (alertHandler != null)
304 {
305 alertHandler.finalizeAlertHandler();
306 }
307 }
308
309 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
310 }
311
312
313 // Get the class for the alert handler. If the handler is already enabled,
314 // then we shouldn't do anything with it although if the class has changed
315 // then we'll at least need to indicate that administrative action is
316 // required. If the handler is disabled, then instantiate the class and
317 // initialize and register it as an alert handler.
318 String className = configuration.getJavaClass();
319 if (existingHandler != null)
320 {
321 if (! className.equals(existingHandler.getClass().getName()))
322 {
323 adminActionRequired = true;
324 }
325
326 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
327 }
328
329 AlertHandler alertHandler = null;
330 try
331 {
332 alertHandler = loadHandler(className, configuration, true);
333 }
334 catch (InitializationException ie)
335 {
336 if (resultCode == ResultCode.SUCCESS)
337 {
338 resultCode = DirectoryServer.getServerErrorResultCode();
339 }
340
341 messages.add(ie.getMessageObject());
342 }
343
344 if (resultCode == ResultCode.SUCCESS)
345 {
346 alertHandlers.put(configuration.dn(), alertHandler);
347 DirectoryServer.registerAlertHandler(alertHandler);
348 }
349
350 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
351 }
352
353
354
355 /**
356 * Loads the specified class, instantiates it as an alert handler, and
357 * optionally initializes that instance.
358 *
359 * @param className The fully-qualified name of the alert handler class
360 * to load, instantiate, and initialize.
361 * @param configuration The configuration to use to initialize the alert
362 * handler. It must not be {@code null}.
363 * @param initialize Indicates whether the alert handler instance should
364 * be initialized.
365 *
366 * @return The possibly initialized alert handler.
367 *
368 * @throws InitializationException If a problem occurred while attempting to
369 * initialize the alert handler.
370 */
371 private AlertHandler loadHandler(String className,
372 AlertHandlerCfg configuration,
373 boolean initialize)
374 throws InitializationException
375 {
376 try
377 {
378 AlertHandlerCfgDefn definition = AlertHandlerCfgDefn.getInstance();
379 ClassPropertyDefinition propertyDefinition =
380 definition.getJavaClassPropertyDefinition();
381 Class<? extends AlertHandler> handlerClass =
382 propertyDefinition.loadClass(className, AlertHandler.class);
383 AlertHandler handler = handlerClass.newInstance();
384
385 if (initialize)
386 {
387 Method method = handler.getClass().getMethod("initializeAlertHandler",
388 configuration.configurationClass());
389 method.invoke(handler, configuration);
390 }
391 else
392 {
393 Method method =
394 handler.getClass().getMethod("isConfigurationAcceptable",
395 AlertHandlerCfg.class, List.class);
396
397 List<Message> unacceptableReasons = new ArrayList<Message>();
398 Boolean acceptable = (Boolean) method.invoke(handler, configuration,
399 unacceptableReasons);
400 if (! acceptable)
401 {
402 StringBuilder buffer = new StringBuilder();
403 if (! unacceptableReasons.isEmpty())
404 {
405 Iterator<Message> iterator = unacceptableReasons.iterator();
406 buffer.append(iterator.next());
407 while (iterator.hasNext())
408 {
409 buffer.append(". ");
410 buffer.append(iterator.next());
411 }
412 }
413
414 Message message = ERR_CONFIG_ALERTHANDLER_CONFIG_NOT_ACCEPTABLE.get(
415 String.valueOf(configuration.dn()), buffer.toString());
416 throw new InitializationException(message);
417 }
418 }
419
420 return handler;
421 }
422 catch (Exception e)
423 {
424 Message message = ERR_CONFIG_ALERTHANDLER_INITIALIZATION_FAILED.
425 get(className, String.valueOf(configuration.dn()),
426 stackTraceToSingleLineString(e));
427 throw new InitializationException(message, e);
428 }
429 }
430 }
431