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 legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2006-2008 Sun Microsystems, Inc.
025 *      Portions Copyright 2013-2015 ForgeRock AS
026 */
027package org.opends.server.core;
028
029import static org.opends.messages.ConfigMessages.*;
030
031import java.util.ArrayList;
032import java.util.List;
033
034import org.forgerock.i18n.LocalizableMessage;
035import org.forgerock.i18n.slf4j.LocalizedLogger;
036import org.forgerock.opendj.config.server.ConfigException;
037import org.forgerock.opendj.ldap.ResultCode;
038import org.opends.server.admin.server.ConfigurationAddListener;
039import org.opends.server.admin.server.ConfigurationDeleteListener;
040import org.opends.server.admin.server.ServerManagementContext;
041import org.opends.server.admin.std.server.AccessLogPublisherCfg;
042import org.opends.server.admin.std.server.DebugLogPublisherCfg;
043import org.opends.server.admin.std.server.ErrorLogPublisherCfg;
044import org.opends.server.admin.std.server.HTTPAccessLogPublisherCfg;
045import org.opends.server.admin.std.server.LogPublisherCfg;
046import org.opends.server.admin.std.server.RootCfg;
047import org.opends.server.loggers.AbstractLogger;
048import org.opends.server.loggers.AccessLogger;
049import org.opends.server.loggers.DebugLogger;
050import org.opends.server.loggers.ErrorLogger;
051import org.opends.server.loggers.HTTPAccessLogger;
052import org.forgerock.opendj.config.server.ConfigChangeResult;
053import org.opends.server.types.InitializationException;
054
055/**
056 * This class defines a utility that will be used to manage the set of loggers
057 * used in the Directory Server.  It will perform the logger initialization when
058 * the server is starting, and then will manage any additions, removals, or
059 * modifications of any loggers while the server is running.
060 */
061public class LoggerConfigManager implements
062    ConfigurationAddListener<LogPublisherCfg>,
063    ConfigurationDeleteListener<LogPublisherCfg>
064{
065
066  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
067
068  private final ServerContext serverContext;
069
070  /**
071   * Create the logger config manager with the provided
072   * server context.
073   *
074   * @param context
075   *            The server context.
076   */
077  public LoggerConfigManager(final ServerContext context)
078  {
079    this.serverContext = context;
080  }
081
082  /**
083   * Initializes all the log publishers.
084   *
085   * @throws ConfigException
086   *           If an unrecoverable problem arises in the process of
087   *           performing the initialization as a result of the server
088   *           configuration.
089   * @throws InitializationException
090   *           If a problem occurs during initialization that is not
091   *           related to the server configuration.
092   */
093  public void initializeLoggerConfig()
094      throws ConfigException, InitializationException
095  {
096    // Create an internal server management context and retrieve
097    // the root configuration which has the log publisher relation.
098    ServerManagementContext context = ServerManagementContext.getInstance();
099    RootCfg root = context.getRootConfiguration();
100
101    root.addLogPublisherAddListener(this);
102    root.addLogPublisherDeleteListener(this);
103
104    List<DebugLogPublisherCfg> debugPublisherCfgs = new ArrayList<>();
105    List<AccessLogPublisherCfg> accessPublisherCfgs = new ArrayList<>();
106    List<HTTPAccessLogPublisherCfg> httpAccessPublisherCfgs = new ArrayList<>();
107    List<ErrorLogPublisherCfg> errorPublisherCfgs = new ArrayList<>();
108
109    for (String name : root.listLogPublishers())
110    {
111      LogPublisherCfg config = root.getLogPublisher(name);
112
113      if(config instanceof DebugLogPublisherCfg)
114      {
115        debugPublisherCfgs.add((DebugLogPublisherCfg)config);
116      }
117      else if(config instanceof AccessLogPublisherCfg)
118      {
119        accessPublisherCfgs.add((AccessLogPublisherCfg)config);
120      }
121      else if (config instanceof HTTPAccessLogPublisherCfg)
122      {
123        httpAccessPublisherCfgs.add((HTTPAccessLogPublisherCfg) config);
124      }
125      else if(config instanceof ErrorLogPublisherCfg)
126      {
127        errorPublisherCfgs.add((ErrorLogPublisherCfg)config);
128      }
129      else
130      {
131        throw new ConfigException(ERR_CONFIG_LOGGER_INVALID_OBJECTCLASS.get(config.dn()));
132      }
133    }
134
135    // See if there are active loggers in all categories.  If not, then log a
136    // message.
137    // Do not output warn message for debug loggers because it is valid to fully
138    // disable all debug loggers.
139    if (accessPublisherCfgs.isEmpty())
140    {
141      logger.warn(WARN_CONFIG_LOGGER_NO_ACTIVE_ACCESS_LOGGERS);
142    }
143    if (errorPublisherCfgs.isEmpty())
144    {
145      logger.warn(WARN_CONFIG_LOGGER_NO_ACTIVE_ERROR_LOGGERS);
146    }
147
148    DebugLogger.getInstance().initializeLogger(debugPublisherCfgs, serverContext);
149    AccessLogger.getInstance().initializeLogger(accessPublisherCfgs, serverContext);
150    HTTPAccessLogger.getInstance().initializeLogger(httpAccessPublisherCfgs, serverContext);
151    ErrorLogger.getInstance().initializeLogger(errorPublisherCfgs, serverContext);
152  }
153
154  /**
155   * Returns the logger instance corresponding to the provided config. If no
156   * logger corresponds to it, null will be returned and a message will be added
157   * to the provided messages list.
158   *
159   * @param config
160   *          the config for which to return the logger instance
161   * @param messages
162   *          where the error message will be output if no logger correspond to
163   *          the provided config.
164   * @return the logger corresponding to the provided config, null if no logger
165   *         corresponds.
166   */
167  private AbstractLogger getLoggerInstance(LogPublisherCfg config,
168      List<LocalizableMessage> messages)
169  {
170    if (config instanceof DebugLogPublisherCfg)
171    {
172      return DebugLogger.getInstance();
173    }
174    else if (config instanceof AccessLogPublisherCfg)
175    {
176      return AccessLogger.getInstance();
177    }
178    else if (config instanceof HTTPAccessLogPublisherCfg)
179    {
180      return HTTPAccessLogger.getInstance();
181    }
182    else if (config instanceof ErrorLogPublisherCfg)
183    {
184      return ErrorLogger.getInstance();
185    }
186    else
187    {
188      messages.add(ERR_CONFIG_LOGGER_INVALID_OBJECTCLASS.get(config.dn()));
189      return null;
190    }
191  }
192
193  /** {@inheritDoc} */
194  @Override
195  public boolean isConfigurationAddAcceptable(LogPublisherCfg config,
196                                              List<LocalizableMessage> unacceptableReasons)
197  {
198    AbstractLogger instance = getLoggerInstance(config, unacceptableReasons);
199    return instance != null
200        && instance.isConfigurationAddAcceptable(config, unacceptableReasons);
201  }
202
203  /** {@inheritDoc} */
204  @Override
205  public ConfigChangeResult applyConfigurationAdd(LogPublisherCfg config)
206  {
207    final ConfigChangeResult ccr = new ConfigChangeResult();
208    AbstractLogger instance = getLoggerInstance(config, ccr.getMessages());
209    if (instance != null)
210    {
211      return instance.applyConfigurationAdd(config);
212    }
213    else
214    {
215      ccr.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
216      return ccr;
217    }
218  }
219
220  /** {@inheritDoc} */
221  @Override
222  public boolean isConfigurationDeleteAcceptable(LogPublisherCfg config,
223                                              List<LocalizableMessage> unacceptableReasons)
224  {
225    AbstractLogger instance = getLoggerInstance(config, unacceptableReasons);
226    return instance != null
227        && instance.isConfigurationDeleteAcceptable(config, unacceptableReasons);
228  }
229
230  /** {@inheritDoc} */
231  @Override
232  public ConfigChangeResult applyConfigurationDelete(LogPublisherCfg config)
233  {
234    final ConfigChangeResult ccr = new ConfigChangeResult();
235    AbstractLogger instance = getLoggerInstance(config, ccr.getMessages());
236    if (instance != null)
237    {
238      return instance.applyConfigurationDelete(config);
239    }
240    else
241    {
242      ccr.setResultCode(ResultCode.UNWILLING_TO_PERFORM);
243      return ccr;
244    }
245  }
246}