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.loggers;
028    import org.opends.messages.Message;
029    
030    import java.io.File;
031    import java.lang.reflect.Method;
032    import java.util.Arrays;
033    import java.util.ArrayList;
034    import java.util.List;
035    
036    import static org.opends.server.loggers.debug.DebugLogger.*;
037    import static org.opends.messages.LoggerMessages.*;
038    import org.opends.server.loggers.debug.DebugTracer;
039    import org.opends.server.types.DebugLogLevel;
040    import org.opends.server.types.ResultCode;
041    import org.opends.server.types.ConfigChangeResult;
042    import org.opends.server.types.DirectoryException;
043    import org.opends.server.admin.std.server.FreeDiskSpaceLogRetentionPolicyCfg;
044    import org.opends.server.admin.server.ConfigurationChangeListener;
045    import org.opends.server.core.DirectoryServer;
046    import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
047    
048    
049    /**
050     * This class implements a retention policy based on the free disk
051     * space available expressed as a percentage. This policy is only
052     * available on Java 6.
053     */
054    public class FreeDiskSpaceRetentionPolicy implements
055        RetentionPolicy<FreeDiskSpaceLogRetentionPolicyCfg>,
056        ConfigurationChangeListener<FreeDiskSpaceLogRetentionPolicyCfg>
057    {
058      /**
059       * The tracer object for the debug logger.
060       */
061      private static final DebugTracer TRACER = getTracer();
062    
063      private long freeDiskSpace = 0;
064      private FreeDiskSpaceLogRetentionPolicyCfg config;
065    
066      /**
067       * {@inheritDoc}
068       */
069      public void initializeLogRetentionPolicy(
070          FreeDiskSpaceLogRetentionPolicyCfg config)
071      {
072        this.freeDiskSpace = config.getFreeDiskSpace();
073        this.config = config;
074    
075        config.addFreeDiskSpaceChangeListener(this);
076      }
077    
078      /**
079       * {@inheritDoc}
080       */
081      public boolean isConfigurationChangeAcceptable(
082          FreeDiskSpaceLogRetentionPolicyCfg config,
083          List<Message> unacceptableReasons)
084      {
085        // Changes should always be OK
086        return true;
087      }
088    
089      /**
090       * {@inheritDoc}
091       */
092      public ConfigChangeResult applyConfigurationChange(
093          FreeDiskSpaceLogRetentionPolicyCfg config)
094      {
095        // Default result code.
096        ResultCode resultCode = ResultCode.SUCCESS;
097        boolean adminActionRequired = false;
098        ArrayList<Message> messages = new ArrayList<Message>();
099    
100        this.freeDiskSpace = config.getFreeDiskSpace();
101        this.config = config;
102    
103        return new ConfigChangeResult(resultCode, adminActionRequired, messages);
104      }
105    
106      /**
107       * {@inheritDoc}
108       */
109      public File[] deleteFiles(FileNamingPolicy fileNamingPolicy)
110          throws DirectoryException
111      {
112        File[] files = fileNamingPolicy.listFiles();
113        if(files == null)
114        {
115          Message message =
116              ERR_LOGGER_ERROR_LISTING_FILES.get(
117                  fileNamingPolicy.getInitialName().toString());
118          throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
119                                       message);
120        }
121    
122        ArrayList<File> filesToDelete = new ArrayList<File>();
123    
124        if(files.length <= 0)
125        {
126          return new File[0];
127        }
128    
129        long freeSpace = 0;
130    
131        try
132        {
133          // Use reflection to see use the getFreeSpace method if available.
134          // this method is only available on Java 6.
135          Method meth = File.class.getMethod("getFreeSpace", new Class[0]);
136          Object value = meth.invoke(files[0]);
137          freeSpace = ((Long) value).longValue();
138        }
139        catch (Exception e)
140        {
141          if (debugEnabled())
142          {
143            TRACER.debugCaught(DebugLogLevel.ERROR, e);
144          }
145          Message message =
146              ERR_LOGGER_ERROR_OBTAINING_FREE_SPACE.get(files[0].toString(),
147                  stackTraceToSingleLineString(e));
148          throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
149                                       message, e);
150        }
151    
152        if(debugEnabled())
153        {
154          TRACER.debugInfo("Current free disk space: %d, Required: %d", freeSpace,
155              freeDiskSpace);
156        }
157    
158        if (freeSpace > freeDiskSpace)
159        {
160          // No cleaning needed.
161          return new File[0];
162        }
163    
164        long freeSpaceNeeded = freeDiskSpace - freeSpace;
165    
166        // Sort files based on last modified time.
167        Arrays.sort(files, new FileComparator());
168    
169        long freedSpace = 0;
170        for (int j = files.length - 1; j < 1; j--)
171        {
172          freedSpace += files[j].length();
173          filesToDelete.add(files[j]);
174          if (freedSpace >= freeSpaceNeeded)
175          {
176            break;
177          }
178        }
179    
180        return filesToDelete.toArray(new File[0]);
181      }
182    
183      /**
184       * {@inheritDoc}
185       */
186      public String toString()
187      {
188        return "Free Disk Retention Policy " + config.dn().toString();
189      }
190    }
191