001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2006-2008 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017package org.opends.server.core;
018import java.util.List;
019
020import org.forgerock.i18n.LocalizableMessage;
021import org.forgerock.i18n.slf4j.LocalizedLogger;
022import org.opends.server.loggers.RotationPolicy;
023import org.forgerock.opendj.config.server.ConfigurationAddListener;
024import org.forgerock.opendj.config.server.ConfigurationDeleteListener;
025import org.forgerock.opendj.config.server.ConfigurationChangeListener;
026import org.forgerock.opendj.server.config.server.LogRotationPolicyCfg;
027import org.forgerock.opendj.server.config.server.RootCfg;
028import org.forgerock.opendj.server.config.meta.LogRotationPolicyCfgDefn;
029import org.forgerock.opendj.config.ClassPropertyDefinition;
030import org.opends.server.types.InitializationException;
031import org.forgerock.opendj.config.server.ConfigChangeResult;
032import org.forgerock.opendj.config.server.ConfigException;
033
034import static org.opends.messages.ConfigMessages.*;
035import static org.opends.server.util.StaticUtils.*;
036
037/**
038 * This class defines a utility that will be used to manage the set of
039 * log rotation policies used in the Directory Server.  It will perform the
040 * initialization when the server is starting, and then will manage any
041 * additions, and removals of policies while the server is running.
042 */
043public class LogRotationPolicyConfigManager implements
044    ConfigurationAddListener<LogRotationPolicyCfg>,
045    ConfigurationDeleteListener<LogRotationPolicyCfg>,
046    ConfigurationChangeListener<LogRotationPolicyCfg>
047{
048  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
049
050  private final ServerContext serverContext;
051
052  /**
053   * Creates this log rotation policy manager.
054   *
055   * @param serverContext
056   *          The server context.
057   */
058  public LogRotationPolicyConfigManager(ServerContext serverContext)
059  {
060    this.serverContext = serverContext;
061  }
062
063  /**
064   * Initializes all the log rotation policies.
065   *
066   * @throws ConfigException
067   *           If an unrecoverable problem arises in the process of performing
068   *           the initialization as a result of the server configuration.
069   * @throws InitializationException
070   *           If a problem occurs during initialization that is not related to
071   *           the server configuration.
072   */
073  public void initializeLogRotationPolicyConfig() throws ConfigException, InitializationException
074  {
075    RootCfg root = serverContext.getRootConfig();
076    root.addLogRotationPolicyAddListener(this);
077    root.addLogRotationPolicyDeleteListener(this);
078
079    for(String name : root.listLogRotationPolicies())
080    {
081      LogRotationPolicyCfg config = root.getLogRotationPolicy(name);
082      RotationPolicy<LogRotationPolicyCfg> rotationPolicy = getRotationPolicy(config);
083      DirectoryServer.registerRotationPolicy(config.dn(), rotationPolicy);
084    }
085  }
086
087  @Override
088  public boolean isConfigurationAddAcceptable(
089      LogRotationPolicyCfg configuration,
090      List<LocalizableMessage> unacceptableReasons)
091  {
092    return isJavaClassAcceptable(configuration, unacceptableReasons);
093  }
094
095  @Override
096  public boolean isConfigurationDeleteAcceptable(
097      LogRotationPolicyCfg configuration,
098      List<LocalizableMessage> unacceptableReasons)
099  {
100    // TODO: Make sure nothing is using this policy before deleting it.
101    return true;
102  }
103
104  @Override
105  public ConfigChangeResult applyConfigurationAdd(LogRotationPolicyCfg config)
106  {
107    final ConfigChangeResult ccr = new ConfigChangeResult();
108
109    try
110    {
111      RotationPolicy<LogRotationPolicyCfg> rotationPolicy = getRotationPolicy(config);
112      DirectoryServer.registerRotationPolicy(config.dn(), rotationPolicy);
113    }
114    catch (ConfigException e) {
115      logger.traceException(e);
116      ccr.addMessage(e.getMessageObject());
117      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
118    } catch (Exception e) {
119      logger.traceException(e);
120
121      ccr.addMessage(ERR_CONFIG_ROTATION_POLICY_CANNOT_CREATE_POLICY.get(config.dn(),
122              stackTraceToSingleLineString(e)));
123      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
124    }
125
126    return ccr;
127  }
128
129  @Override
130  public ConfigChangeResult applyConfigurationDelete(
131      LogRotationPolicyCfg config)
132  {
133    final ConfigChangeResult ccr = new ConfigChangeResult();
134
135    RotationPolicy<?> policy = DirectoryServer.getRotationPolicy(config.dn());
136    if(policy != null)
137    {
138      DirectoryServer.deregisterRotationPolicy(config.dn());
139    }
140    else
141    {
142      // TODO: Add message and check for usage
143      ccr.setResultCode(DirectoryServer.getServerErrorResultCode());
144    }
145
146    return ccr;
147  }
148
149  @Override
150  public boolean isConfigurationChangeAcceptable(
151      LogRotationPolicyCfg configuration,
152      List<LocalizableMessage> unacceptableReasons)
153  {
154    return isJavaClassAcceptable(configuration, unacceptableReasons);
155  }
156
157  @Override
158  public ConfigChangeResult applyConfigurationChange(
159      LogRotationPolicyCfg configuration)
160  {
161    final ConfigChangeResult ccr = new ConfigChangeResult();
162
163    RotationPolicy<?> policy = DirectoryServer.getRotationPolicy(configuration.dn());
164    String className = configuration.getJavaClass();
165    if(!className.equals(policy.getClass().getName()))
166    {
167      ccr.setAdminActionRequired(true);
168    }
169
170    return ccr;
171  }
172
173  private boolean isJavaClassAcceptable(LogRotationPolicyCfg config,
174                                        List<LocalizableMessage> unacceptableReasons)
175  {
176    String className = config.getJavaClass();
177    LogRotationPolicyCfgDefn d = LogRotationPolicyCfgDefn.getInstance();
178    ClassPropertyDefinition pd = d.getJavaClassPropertyDefinition();
179    try {
180      Class<? extends RotationPolicy> theClass =
181          pd.loadClass(className, RotationPolicy.class);
182      // Explicitly cast to check that implementation implements the correct interface.
183      RotationPolicy<?> retentionPolicy = theClass.newInstance();
184      // next line is here to ensure that eclipse does not remove the cast in the line above
185      retentionPolicy.hashCode();
186      return true;
187    } catch (Exception e) {
188      unacceptableReasons.add(
189          ERR_CONFIG_ROTATION_POLICY_INVALID_CLASS.get(className, config.dn(), e));
190      return false;
191    }
192  }
193
194  private RotationPolicy<LogRotationPolicyCfg> getRotationPolicy(LogRotationPolicyCfg config)
195      throws ConfigException {
196    String className = config.getJavaClass();
197    LogRotationPolicyCfgDefn d = LogRotationPolicyCfgDefn.getInstance();
198    ClassPropertyDefinition pd = d.getJavaClassPropertyDefinition();
199    try {
200      Class<? extends RotationPolicy> theClass =
201          pd.loadClass(className, RotationPolicy.class);
202      RotationPolicy<LogRotationPolicyCfg> rotationPolicy = theClass.newInstance();
203      rotationPolicy.initializeLogRotationPolicy(config);
204      return rotationPolicy;
205    } catch (Exception e) {
206      LocalizableMessage message = ERR_CONFIG_ROTATION_POLICY_INVALID_CLASS.get(
207          className, config.dn(), e);
208      throw new ConfigException(message, e);
209    }
210  }
211}