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 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
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 * docs/licenses/cddl.txt.  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 *      Portions Copyright 2010-2023 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.common.scripting;
028
029
030
031import java.util.List;
032
033import com.unboundid.directory.sdk.broker.internal.BrokerExtension;
034import com.unboundid.directory.sdk.common.config.AlertHandlerConfig;
035import com.unboundid.directory.sdk.common.internal.Reconfigurable;
036import com.unboundid.directory.sdk.common.types.AlertNotification;
037import com.unboundid.directory.sdk.common.types.ServerContext;
038import com.unboundid.directory.sdk.metrics.internal.MetricsEngineExtension;
039import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
040import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
041import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
042import com.unboundid.ldap.sdk.LDAPException;
043import com.unboundid.ldap.sdk.ResultCode;
044import com.unboundid.util.Extensible;
045import com.unboundid.util.ThreadSafety;
046import com.unboundid.util.ThreadSafetyLevel;
047import com.unboundid.util.args.ArgumentException;
048import com.unboundid.util.args.ArgumentParser;
049
050
051
052/**
053 * This class defines an API that must be implemented by scripted extensions
054 * which will be invoked whenever an administrative alert is generated within
055 * the server.  Administrative alerts may be used to notify administrators
056 * whenever a significant error, warning, or other type of event occurs within
057 * the server.  Alert handlers may be used to help ensure that those
058 * notifications are made available to administrators in an appropriate manner.
059 * <BR><BR>
060 * Each alert handler may be configured so that it will only be invoked for
061 * certain types of alerts, either based on the specific alert type or based on
062 * the alert severity.  This is handled automatically by the server, so
063 * individual alert handler implementations do not need to attempt to perform
064 * that filtering on their own.  However, they may perform additional processing
065 * if desired to further narrow the set of alerts that should be made available
066 * to administrators.
067 * <BR>
068 * <H2>Configuring Groovy-Scripted Alert Handlers</H2>
069 * In order to configure a scripted alert handler based on this API and written
070 * in the Groovy scripting language, use a command like:
071 * <PRE>
072 *      dsconfig create-alert-handler \
073 *           --handler-name "<I>{handler-name}</I>" \
074 *           --type groovy-scripted \
075 *           --set enabled:true \
076 *           --set "script-class:<I>{class-name}</I>" \
077 *           --set "script-argument:<I>{name=value}</I>"
078 * </PRE>
079 * where "<I>{handler-name}</I>" is the name to use for the alert handler
080 * instance, "<I>{class-name}</I>" is the fully-qualified name of the Groovy
081 * class written using this API, and "<I>{name=value}</I>" represents name-value
082 * pairs for any arguments to provide to the alert handler.  If multiple
083 * arguments should be provided to the alert handler, then the
084 * "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be
085 * provided multiple times.
086 *
087 * @see  com.unboundid.directory.sdk.common.api.AlertHandler
088 */
089@Extensible()
090@DirectoryServerExtension()
091@DirectoryProxyServerExtension(appliesToLocalContent=true,
092     appliesToRemoteContent=false)
093@SynchronizationServerExtension(appliesToLocalContent=true,
094     appliesToSynchronizedContent=false)
095@MetricsEngineExtension()
096@BrokerExtension()
097@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
098public abstract class ScriptedAlertHandler
099       implements Reconfigurable<AlertHandlerConfig>
100{
101  /**
102   * Creates a new instance of this alert handler.  All alert handler
103   * implementations must include a default constructor, but any initialization
104   * should generally be done in the {@code initializeAlertHandler} method.
105   */
106  public ScriptedAlertHandler()
107  {
108    // No implementation is required.
109  }
110
111
112
113  /**
114   * {@inheritDoc}
115   */
116  public void defineConfigArguments(final ArgumentParser parser)
117         throws ArgumentException
118  {
119    // No arguments will be allowed by default.
120  }
121
122
123
124  /**
125   * Initializes this alert handler.
126   *
127   * @param  serverContext  A handle to the server context for the server in
128   *                        which this extension is running.
129   * @param  config         The general configuration for this alert handler.
130   * @param  parser         The argument parser which has been initialized from
131   *                        the configuration for this alert handler.
132   *
133   * @throws  LDAPException  If a problem occurs while initializing this alert
134   *                         handler.
135   */
136  public void initializeAlertHandler(final ServerContext serverContext,
137                                     final AlertHandlerConfig config,
138                                     final ArgumentParser parser)
139         throws LDAPException
140  {
141    // No initialization will be performed by default.
142  }
143
144
145
146  /**
147   * Performs any cleanup which may be necessary when this alert handler is to
148   * be taken out of service.
149   */
150  public void finalizeAlertHandler()
151  {
152    // No implementation is required.
153  }
154
155
156
157  /**
158   * {@inheritDoc}
159   */
160  public boolean isConfigurationAcceptable(final AlertHandlerConfig config,
161                      final ArgumentParser parser,
162                      final List<String> unacceptableReasons)
163  {
164    // No extended validation will be performed.
165    return true;
166  }
167
168
169
170  /**
171   * {@inheritDoc}
172   */
173  public ResultCode applyConfiguration(final AlertHandlerConfig config,
174                                       final ArgumentParser parser,
175                                       final List<String> adminActionsRequired,
176                                       final List<String> messages)
177  {
178    // By default, no configuration changes will be applied.  If there are any
179    // arguments, then add an admin action message indicating that the extension
180    // needs to be restarted for any changes to take effect.
181    if (! parser.getNamedArguments().isEmpty())
182    {
183      adminActionsRequired.add(
184           "No configuration change has actually been applied.  The new " +
185                "configuration will not take effect until this alert handler " +
186                "is disabled and re-enabled or until the server is restarted.");
187    }
188
189    return ResultCode.SUCCESS;
190  }
191
192
193
194  /**
195   * Performs any processing which may be necessary to handle the provided alert
196   * notification.
197   *
198   * @param  alert  The alert notification generated within the server.
199   */
200  public abstract void handleAlert(final AlertNotification alert);
201}