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    import org.opends.server.loggers.RotationPolicy;
031    import org.opends.server.admin.server.ConfigurationAddListener;
032    import org.opends.server.admin.server.ConfigurationDeleteListener;
033    import org.opends.server.admin.server.ServerManagementContext;
034    import org.opends.server.admin.server.ConfigurationChangeListener;
035    import org.opends.server.admin.std.server.LogRotationPolicyCfg;
036    import org.opends.server.admin.std.server.RootCfg;
037    import org.opends.server.admin.std.meta.LogRotationPolicyCfgDefn;
038    import org.opends.server.admin.ClassPropertyDefinition;
039    import org.opends.server.types.InitializationException;
040    import org.opends.server.types.ConfigChangeResult;
041    import org.opends.server.types.ResultCode;
042    import org.opends.server.types.DebugLogLevel;
043    import org.opends.server.config.ConfigException;
044    
045    import static org.opends.server.loggers.debug.DebugLogger.*;
046    import org.opends.server.loggers.debug.DebugTracer;
047    import static org.opends.messages.ConfigMessages.*;
048    
049    import static org.opends.server.util.StaticUtils.*;
050    
051    import java.util.List;
052    import java.util.ArrayList;
053    import java.lang.reflect.Method;
054    import java.lang.reflect.InvocationTargetException;
055    
056    /**
057     * This class defines a utility that will be used to manage the set of
058     * log rotation policies used in the Directory Server.  It will perform the
059     * initialization when the server is starting, and then will manage any
060     * additions, and removals of policies while the server is running.
061     */
062    public class LogRotationPolicyConfigManager implements
063        ConfigurationAddListener<LogRotationPolicyCfg>,
064        ConfigurationDeleteListener<LogRotationPolicyCfg>,
065        ConfigurationChangeListener<LogRotationPolicyCfg>
066    {
067      /**
068       * The tracer object for the debug logger.
069       */
070      private static final DebugTracer TRACER = getTracer();
071    
072    
073      /**
074       * Initializes all the log rotation policies.
075       *
076       * @throws ConfigException
077       *           If an unrecoverable problem arises in the process of
078       *           performing the initialization as a result of the server
079       *           configuration.
080       * @throws InitializationException
081       *           If a problem occurs during initialization that is not
082       *           related to the server configuration.
083       */
084      public void initializeLogRotationPolicyConfig()
085          throws ConfigException, InitializationException
086      {
087        ServerManagementContext context = ServerManagementContext.getInstance();
088        RootCfg root = context.getRootConfiguration();
089    
090        root.addLogRotationPolicyAddListener(this);
091        root.addLogRotationPolicyDeleteListener(this);
092    
093        for(String name : root.listLogRotationPolicies())
094        {
095          LogRotationPolicyCfg config = root.getLogRotationPolicy(name);
096    
097          RotationPolicy rotationPolicy = getRotationPolicy(config);
098    
099          DirectoryServer.registerRotationPolicy(config.dn(), rotationPolicy);
100        }
101      }
102    
103      /**
104       * {@inheritDoc}
105       */
106      public boolean isConfigurationAddAcceptable(
107          LogRotationPolicyCfg configuration,
108          List<Message> unacceptableReasons)
109      {
110        return isJavaClassAcceptable(configuration, unacceptableReasons);
111      }
112    
113      /**
114       * {@inheritDoc}
115       */
116      public boolean isConfigurationDeleteAcceptable(
117          LogRotationPolicyCfg configuration,
118          List<Message> unacceptableReasons)
119      {
120        // TODO: Make sure nothing is using this policy before deleting it.
121        return true;
122      }
123    
124      /**
125       * {@inheritDoc}
126       */
127      public ConfigChangeResult applyConfigurationAdd(LogRotationPolicyCfg config)
128      {
129        // Default result code.
130        ResultCode resultCode = ResultCode.SUCCESS;
131        boolean adminActionRequired = false;
132        ArrayList<Message> messages = new ArrayList<Message>();
133    
134        try
135        {
136          RotationPolicy rotationPolicy = getRotationPolicy(config);
137    
138          DirectoryServer.registerRotationPolicy(config.dn(), rotationPolicy);
139        }
140        catch (ConfigException e) {
141          if (debugEnabled())
142          {
143            TRACER.debugCaught(DebugLogLevel.ERROR, e);
144          }
145          messages.add(e.getMessageObject());
146          resultCode = DirectoryServer.getServerErrorResultCode();
147        } catch (Exception e) {
148          if (debugEnabled())
149          {
150            TRACER.debugCaught(DebugLogLevel.ERROR, e);
151          }
152    
153          messages.add(ERR_CONFIG_ROTATION_POLICY_CANNOT_CREATE_POLICY.get(
154                  String.valueOf(config.dn().toString()),
155                  stackTraceToSingleLineString(e)));
156          resultCode = DirectoryServer.getServerErrorResultCode();
157        }
158    
159        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
160      }
161    
162      /**
163       * {@inheritDoc}
164       */
165      public ConfigChangeResult applyConfigurationDelete(
166          LogRotationPolicyCfg config)
167      {
168        // Default result code.
169        ResultCode resultCode = ResultCode.SUCCESS;
170        boolean adminActionRequired = false;
171        ArrayList<Message> messages = new ArrayList<Message>();
172    
173        RotationPolicy policy = DirectoryServer.getRotationPolicy(config.dn());
174        if(policy != null)
175        {
176          DirectoryServer.deregisterRotationPolicy(config.dn());
177        }
178        else
179        {
180          // TODO: Add message and check for usage
181          resultCode = DirectoryServer.getServerErrorResultCode();
182        }
183    
184        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
185      }
186    
187      /**
188       * {@inheritDoc}
189       */
190      public boolean isConfigurationChangeAcceptable(
191          LogRotationPolicyCfg configuration,
192          List<Message> unacceptableReasons)
193      {
194        return isJavaClassAcceptable(configuration, unacceptableReasons);
195      }
196    
197      /**
198       * {@inheritDoc}
199       */
200      public ConfigChangeResult applyConfigurationChange(
201          LogRotationPolicyCfg configuration)
202      {
203        // Default result code.
204        ResultCode resultCode = ResultCode.SUCCESS;
205        boolean adminActionRequired = false;
206        ArrayList<Message> messages = new ArrayList<Message>();
207    
208        RotationPolicy policy =
209            DirectoryServer.getRotationPolicy(configuration.dn());
210        String className = configuration.getJavaClass();
211        if(!className.equals(policy.getClass().getName()))
212        {
213          adminActionRequired = true;
214        }
215    
216        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
217      }
218    
219      private boolean isJavaClassAcceptable(LogRotationPolicyCfg config,
220                                            List<Message> unacceptableReasons)
221      {
222        String className = config.getJavaClass();
223        LogRotationPolicyCfgDefn d = LogRotationPolicyCfgDefn.getInstance();
224        ClassPropertyDefinition pd =
225            d.getJavaClassPropertyDefinition();
226        // Load the class and cast it to a RotationPolicy.
227        Class<? extends RotationPolicy> theClass;
228        try {
229          theClass = pd.loadClass(className, RotationPolicy.class);
230          theClass.newInstance();
231        } catch (Exception e) {
232          Message message = ERR_CONFIG_ROTATION_POLICY_INVALID_CLASS.get(className,
233                                      config.dn().toString(),
234                                      String.valueOf(e));
235          unacceptableReasons.add(message);
236          return false;
237        }
238        // Check that the implementation class implements the correct interface.
239        try {
240          // Determine the initialization method to use: it must take a
241          // single parameter which is the exact type of the configuration
242          // object.
243          theClass.getMethod("initializeLogRotationPolicy", config
244              .configurationClass());
245        } catch (Exception e) {
246          Message message = ERR_CONFIG_ROTATION_POLICY_INVALID_CLASS.get(className,
247                                      config.dn().toString(),
248                                      String.valueOf(e));
249          unacceptableReasons.add(message);
250          return false;
251        }
252        // The class is valid as far as we can tell.
253        return true;
254      }
255    
256      private RotationPolicy getRotationPolicy(LogRotationPolicyCfg config)
257          throws ConfigException {
258        String className = config.getJavaClass();
259        LogRotationPolicyCfgDefn d = LogRotationPolicyCfgDefn.getInstance();
260        ClassPropertyDefinition pd =
261            d.getJavaClassPropertyDefinition();
262        // Load the class and cast it to a RotationPolicy.
263        Class<? extends RotationPolicy> theClass;
264        RotationPolicy rotationPolicy;
265        try {
266          theClass = pd.loadClass(className, RotationPolicy.class);
267          rotationPolicy = theClass.newInstance();
268    
269          // Determine the initialization method to use: it must take a
270          // single parameter which is the exact type of the configuration
271          // object.
272          Method method = theClass.getMethod("initializeLogRotationPolicy", config
273              .configurationClass());
274          method.invoke(rotationPolicy, config);
275        }
276        catch (InvocationTargetException ite)
277        {
278          // Rethrow the exceptions thrown be the invoked method.
279          Throwable e = ite.getTargetException();
280          Message message = ERR_CONFIG_ROTATION_POLICY_INVALID_CLASS.get(
281              className, config.dn().toString(), stackTraceToSingleLineString(e));
282          throw new ConfigException(message, e);
283        } catch (Exception e) {
284          Message message = ERR_CONFIG_ROTATION_POLICY_INVALID_CLASS.get(
285              className, config.dn().toString(), String.valueOf(e));
286          throw new ConfigException(message, e);
287        }
288    
289        // The connection handler has been successfully initialized.
290        return rotationPolicy;
291      }
292    }