gnunet-android

GNUnet for Android
Log | Files | Refs | README

CloseGuard.java (6934B)


      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 /*
     17 ** Modified to support SQLite extensions by the SQLite developers: 
     18 ** sqlite-dev@sqlite.org.
     19 */
     20 
     21 package org.sqlite.database.sqlite;
     22 import android.util.Log;
     23 
     24 /**
     25  * CloseGuard is a mechanism for flagging implicit finalizer cleanup of
     26  * resources that should have been cleaned up by explicit close
     27  * methods (aka "explicit termination methods" in Effective Java).
     28  * <p>
     29  * A simple example: <pre>   {@code
     30  *   class Foo {
     31  *
     32  *       private final CloseGuard guard = CloseGuard.get();
     33  *
     34  *       ...
     35  *
     36  *       public Foo() {
     37  *           ...;
     38  *           guard.open("cleanup");
     39  *       }
     40  *
     41  *       public void cleanup() {
     42  *          guard.close();
     43  *          ...;
     44  *       }
     45  *
     46  *       protected void finalize() throws Throwable {
     47  *           try {
     48  *               if (guard != null) {
     49  *                   guard.warnIfOpen();
     50  *               }
     51  *               cleanup();
     52  *           } finally {
     53  *               super.finalize();
     54  *           }
     55  *       }
     56  *   }
     57  * }</pre>
     58  *
     59  * In usage where the resource to be explicitly cleaned up are
     60  * allocated after object construction, CloseGuard protection can
     61  * be deferred. For example: <pre>   {@code
     62  *   class Bar {
     63  *
     64  *       private final CloseGuard guard = CloseGuard.get();
     65  *
     66  *       ...
     67  *
     68  *       public Bar() {
     69  *           ...;
     70  *       }
     71  *
     72  *       public void connect() {
     73  *          ...;
     74  *          guard.open("cleanup");
     75  *       }
     76  *
     77  *       public void cleanup() {
     78  *          guard.close();
     79  *          ...;
     80  *       }
     81  *
     82  *       protected void finalize() throws Throwable {
     83  *           try {
     84  *               if (guard != null) {
     85  *                   guard.warnIfOpen();
     86  *               }
     87  *               cleanup();
     88  *           } finally {
     89  *               super.finalize();
     90  *           }
     91  *       }
     92  *   }
     93  * }</pre>
     94  *
     95  * When used in a constructor calls to {@code open} should occur at
     96  * the end of the constructor since an exception that would cause
     97  * abrupt termination of the constructor will mean that the user will
     98  * not have a reference to the object to cleanup explicitly. When used
     99  * in a method, the call to {@code open} should occur just after
    100  * resource acquisition.
    101  *
    102  * <p>
    103  *
    104  * Note that the null check on {@code guard} in the finalizer is to
    105  * cover cases where a constructor throws an exception causing the
    106  * {@code guard} to be uninitialized.
    107  *
    108  * @hide
    109  */
    110 public final class CloseGuard {
    111 
    112     /**
    113      * Instance used when CloseGuard is disabled to avoid allocation.
    114      */
    115     private static final CloseGuard NOOP = new CloseGuard();
    116 
    117     /**
    118      * Enabled by default so we can catch issues early in VM startup.
    119      * Note, however, that Android disables this early in its startup,
    120      * but enables it with DropBoxing for system apps on debug builds.
    121      */
    122     private static volatile boolean ENABLED = true;
    123 
    124     /**
    125      * Hook for customizing how CloseGuard issues are reported.
    126      */
    127     private static volatile Reporter REPORTER = new DefaultReporter();
    128 
    129     /**
    130      * Returns a CloseGuard instance. If CloseGuard is enabled, {@code
    131      * #open(String)} can be used to set up the instance to warn on
    132      * failure to close. If CloseGuard is disabled, a non-null no-op
    133      * instance is returned.
    134      */
    135     public static CloseGuard get() {
    136         if (!ENABLED) {
    137             return NOOP;
    138         }
    139         return new CloseGuard();
    140     }
    141 
    142     /**
    143      * Used to enable or disable CloseGuard. Note that CloseGuard only
    144      * warns if it is enabled for both allocation and finalization.
    145      */
    146     public static void setEnabled(boolean enabled) {
    147         ENABLED = enabled;
    148     }
    149 
    150     /**
    151      * Used to replace default Reporter used to warn of CloseGuard
    152      * violations. Must be non-null.
    153      */
    154     public static void setReporter(Reporter reporter) {
    155         if (reporter == null) {
    156             throw new NullPointerException("reporter == null");
    157         }
    158         REPORTER = reporter;
    159     }
    160 
    161     /**
    162      * Returns non-null CloseGuard.Reporter.
    163      */
    164     public static Reporter getReporter() {
    165         return REPORTER;
    166     }
    167 
    168     private CloseGuard() {}
    169 
    170     /**
    171      * If CloseGuard is enabled, {@code open} initializes the instance
    172      * with a warning that the caller should have explicitly called the
    173      * {@code closer} method instead of relying on finalization.
    174      *
    175      * @param closer non-null name of explicit termination method
    176      * @throws NullPointerException if closer is null, regardless of
    177      * whether or not CloseGuard is enabled
    178      */
    179     public void open(String closer) {
    180         // always perform the check for valid API usage...
    181         if (closer == null) {
    182             throw new NullPointerException("closer == null");
    183         }
    184         // ...but avoid allocating an allocationSite if disabled
    185         if (this == NOOP || !ENABLED) {
    186             return;
    187         }
    188         String message = "Explicit termination method '" + closer + "' not called";
    189         allocationSite = new Throwable(message);
    190     }
    191 
    192     private Throwable allocationSite;
    193 
    194     /**
    195      * Marks this CloseGuard instance as closed to avoid warnings on
    196      * finalization.
    197      */
    198     public void close() {
    199         allocationSite = null;
    200     }
    201 
    202     /**
    203      * If CloseGuard is enabled, logs a warning if the caller did not
    204      * properly cleanup by calling an explicit close method
    205      * before finalization. If CloseGuard is disabled, no action is
    206      * performed.
    207      */
    208     public void warnIfOpen() {
    209         if (allocationSite == null || !ENABLED) {
    210             return;
    211         }
    212 
    213         String message =
    214                 ("A resource was acquired at attached stack trace but never released. "
    215                  + "See java.io.Closeable for information on avoiding resource leaks.");
    216 
    217         REPORTER.report(message, allocationSite);
    218     }
    219 
    220     /**
    221      * Interface to allow customization of reporting behavior.
    222      */
    223     public static interface Reporter {
    224         public void report (String message, Throwable allocationSite);
    225     }
    226 
    227     /**
    228      * Default Reporter which reports CloseGuard violations to the log.
    229      */
    230     private static final class DefaultReporter implements Reporter {
    231         @Override public void report (String message, Throwable allocationSite) {
    232             Log.w(message, allocationSite);
    233         }
    234     }
    235 }