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     *      Copyright 2011-2012 UnboundID Corp.
026     */
027    package com.unboundid.directory.sdk.common.api;
028    
029    
030    
031    import java.util.Collections;
032    import java.util.List;
033    import java.util.Map;
034    
035    import com.unboundid.directory.sdk.common.config.FileBasedErrorLoggerConfig;
036    import com.unboundid.directory.sdk.common.internal.ExampleUsageProvider;
037    import com.unboundid.directory.sdk.common.internal.Reconfigurable;
038    import com.unboundid.directory.sdk.common.internal.UnboundIDExtension;
039    import com.unboundid.directory.sdk.common.types.LogCategory;
040    import com.unboundid.directory.sdk.common.types.LogSeverity;
041    import com.unboundid.directory.sdk.common.types.ServerContext;
042    import com.unboundid.directory.sdk.ds.internal.DirectoryServerExtension;
043    import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
044    import com.unboundid.directory.sdk.sync.internal.SynchronizationServerExtension;
045    import com.unboundid.ldap.sdk.LDAPException;
046    import com.unboundid.ldap.sdk.ResultCode;
047    import com.unboundid.util.Extensible;
048    import com.unboundid.util.ThreadSafety;
049    import com.unboundid.util.ThreadSafetyLevel;
050    import com.unboundid.util.args.ArgumentException;
051    import com.unboundid.util.args.ArgumentParser;
052    
053    
054    
055    /**
056     * This class defines an API that may be used to create a specific type of
057     * error logger which is intended to write log messages to text files.  This is
058     * a convenience for developers which wish to create custom error loggers that
059     * write to text files and provides support for a wide range of functionality
060     * including high-performance and highly-concurrent logging.  All of the options
061     * available to {@link ErrorLogger} implementations are available for
062     * file-based error loggers, as well as options for indicating the log file
063     * path, the rotation and retention policies, whether to buffer the output, etc.
064     * <BR><BR>
065     * Note that file-based error loggers will automatically be registered within
066     * the server as disk space consumers, so there is no need to implement the
067     * {@link DiskSpaceConsumer} interface.  Also note that configuration change
068     * related to the log file (e.g., the log file path, buffer size, queue size,
069     * etc.) will also automatically be handled by the server, so subclasses only
070     * need to be concerned about changes to the custom arguments they define.
071     * <BR>
072     * <H2>Configuring File-BasedError Loggers</H2>
073     * In order to configure a file-based error logger created using this API, use a
074     * command like:
075     * <PRE>
076     *      dsconfig create-log-publisher \
077     *           --publisher-name "<I>{logger-name}</I>" \
078     *           --type third-party-file-based-error \
079     *           --set enabled:true \
080     *           --set "log-file:<I>{path}</I>" \
081     *           --set "rotation-policy:<I>{rotation-policy-name}</I>" \
082     *           --set "retention-policy:<I>{retention-policy-name}</I>" \
083     *           --set "extension-class:<I>{class-name}</I>" \
084     *           --set "extension-argument:<I>{name=value}</I>"
085     * </PRE>
086     * where "<I>{logger-name}</I>" is the name to use for the error logger
087     * instance, "<I>{path}</I>" is the path to the log file to be written,
088     * "<I>{rotation-policy-name}</I>" is the name of the log rotation policy to use
089     * for the log file, "<I>{retention-policy-name}</I>" is the name of the log
090     * retention policy to use for the log file, "<I>{class-name}</I>" is the
091     * fully-qualified name of the Java class that extends
092     * {@code com.unboundid.directory.sdk.common.api.FileBasedErrorLogger}, and
093     * "<I>{name=value}</I>" represents name-value pairs for any arguments to
094     * provide to the logger.  If multiple arguments should be provided to the
095     * logger, then the "<CODE>--set extension-argument:<I>{name=value}</I></CODE>"
096     * option should be provided multiple times.  It is also possible to specify
097     * multiple log rotation and/or retention policies if desired.
098     *
099     * @see  ErrorLogger
100     * @see  com.unboundid.directory.sdk.common.scripting.ScriptedErrorLogger
101     * @see
102     *    com.unboundid.directory.sdk.common.scripting.ScriptedFileBasedErrorLogger
103     */
104    @Extensible()
105    @DirectoryServerExtension()
106    @DirectoryProxyServerExtension(appliesToLocalContent=true,
107         appliesToRemoteContent=true)
108    @SynchronizationServerExtension(appliesToLocalContent=true,
109         appliesToSynchronizedContent=true)
110    @ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
111    public abstract class FileBasedErrorLogger
112           implements UnboundIDExtension,
113                      Reconfigurable<FileBasedErrorLoggerConfig>,
114                      ExampleUsageProvider
115    {
116      /**
117       * Creates a new instance of this file-based error logger.  All file-based
118       * error logger implementations must include a default constructor, but any
119       * initialization should generally be done in the
120       * {@code initializeErrorLogger} method.
121       */
122      public FileBasedErrorLogger()
123      {
124        // No implementation is required.
125      }
126    
127    
128    
129      /**
130       * {@inheritDoc}
131       */
132      public abstract String getExtensionName();
133    
134    
135    
136      /**
137       * {@inheritDoc}
138       */
139      public abstract String[] getExtensionDescription();
140    
141    
142    
143      /**
144       * {@inheritDoc}
145       */
146      public void defineConfigArguments(final ArgumentParser parser)
147             throws ArgumentException
148      {
149        // No arguments will be allowed by default.
150      }
151    
152    
153    
154      /**
155       * Initializes this file-based error logger.
156       *
157       * @param  serverContext  A handle to the server context for the server in
158       *                        which this extension is running.
159       * @param  config         The general configuration for this file-based error
160       *                        logger.
161       * @param  parser         The argument parser which has been initialized from
162       *                        the configuration for this file-based error logger.
163       *
164       * @throws  LDAPException  If a problem occurs while initializing this
165       *                         file-based error logger.
166       */
167      public void initializeErrorLogger(final ServerContext serverContext,
168                                        final FileBasedErrorLoggerConfig config,
169                                        final ArgumentParser parser)
170             throws LDAPException
171      {
172        // No initialization will be performed by default.
173      }
174    
175    
176    
177      /**
178       * {@inheritDoc}
179       */
180      public boolean isConfigurationAcceptable(
181                          final FileBasedErrorLoggerConfig config,
182                          final ArgumentParser parser,
183                          final List<String> unacceptableReasons)
184      {
185        // No extended validation will be performed by default.
186        return true;
187      }
188    
189    
190    
191      /**
192       * {@inheritDoc}
193       */
194      public ResultCode applyConfiguration(final FileBasedErrorLoggerConfig config,
195                                           final ArgumentParser parser,
196                                           final List<String> adminActionsRequired,
197                                           final List<String> messages)
198      {
199        // If there are any custom arguments, then add an admin action message
200        // indicating that the extension needs to be restarted for any changes to
201        // take effect.
202        if (! parser.getNamedArguments().isEmpty())
203        {
204          adminActionsRequired.add(
205               "If any extension-argument values have been altered, then " +
206                    "those new values have not actually been applied.  The new " +
207                    "configuration for those arguments will not take effect " +
208                    "until this file-based error logger is disabled and " +
209                    "re-enabled, or until the server is restarted.");
210        }
211    
212        return ResultCode.SUCCESS;
213      }
214    
215    
216    
217      /**
218       * Performs any cleanup which may be necessary when this file-based error
219       * logger is to be taken out of service.
220       */
221      public void finalizeErrorLogger()
222      {
223        // No implementation is required.
224      }
225    
226    
227    
228      /**
229       * Records information about the provided message, if appropriate.
230       *
231       * @param  category   The category for the message to be logged.
232       * @param  severity   The severity for the message to be logged.
233       * @param  messageID  The unique identifier with which the message text is
234       *                    associated.
235       * @param  message    The message to be logged.
236       *
237       * @return  The content of the log message that should be written.  It may be
238       *          {@code null} or empty if no message should be written.  It may
239       *          optionally include line breaks if the log message should span
240       *          multiple lines.
241       */
242      public abstract CharSequence logError(final LogCategory category,
243                                            final LogSeverity severity,
244                                            final long messageID,
245                                            final String message);
246    
247    
248    
249      /**
250       * {@inheritDoc}
251       */
252      public Map<List<String>,String> getExamplesArgumentSets()
253      {
254        return Collections.emptyMap();
255      }
256    }