Package com.j256.ormlite.android.apptools

Source Code of com.j256.ormlite.android.apptools.OpenHelperManager$SqliteOpenHelperFactory

package com.j256.ormlite.android.apptools;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import android.content.Context;

import com.j256.ormlite.logger.Logger;
import com.j256.ormlite.logger.LoggerFactory;

/**
* This helps organize and access database connections to optimize connection sharing. There are several schemes to
* manage the database connections in an Android app, but as an app gets more complicated, there are many potential
* places where database locks can occur. This class allows database connection sharing between multiple threads in a
* single app.
*
* This gets injected or called with the {@link OrmLiteSqliteOpenHelper} class that is used to manage the database
* connection. The helper instance will be kept in a static field and only released once its internal usage count goes
* to 0.
*
* The SQLiteOpenHelper and database classes maintain one connection under the hood, and prevent locks in the java code.
* Creating multiple connections can potentially be a source of trouble. This class shares the same connection instance
* between multiple clients, which will allow multiple activities and services to run at the same time.
*
* Every time you use the helper, you should call {@link #getHelper(Context)} or {@link #getHelper(Context, Class)}.
* When you are done with the helper you should call {@link #releaseHelper()}.
*
* @author graywatson, kevingalligan
*/
public class OpenHelperManager {

  private static final String HELPER_CLASS_RESOURCE_NAME = "open_helper_classname";
  private static Logger logger = LoggerFactory.getLogger(OpenHelperManager.class);

  private static SqliteOpenHelperFactory factory = null;
  private static Class<? extends OrmLiteSqliteOpenHelper> helperClass = null;
  private static volatile OrmLiteSqliteOpenHelper helper = null;
  private static boolean wasClosed = false;
  private static int instanceCount = 0;
  // private static String LOG_NAME = OpenHelperManager.class.getName();

  /**
   * Set the manager with your own helper factory.
   *
   * @deprecated You should either use {@link #setOpenHelperClass(Class)} or call {@link #getHelper(Context)}.
   */
  @Deprecated
  public static void setOpenHelperFactory(SqliteOpenHelperFactory factory) {
    OpenHelperManager.factory = factory;
  }

  /**
   * If you are _not_ using the {@link OrmLiteBaseActivity} type classes then you will need to call this in a static
   * method in your code.
   */
  public static void setOpenHelperClass(Class<? extends OrmLiteSqliteOpenHelper> openHelperClass) {
    innerSetHelperClass(openHelperClass);
  }

  /**
   * Create a static instance of our open helper. This has a usage counter on it so make sure all calls to this method
   * have an associated call to {@link #releaseHelper()}. This should be called during an onCreate() type of method
   * when the application or service is starting. The caller should then keep the helper around until it is shutting
   * down when {@link #releaseHelper()} should be called.
   *
   * <p>
   * If multiple parts of your application need the helper, they call can call this as long as they each call release
   * when they are done.
   * </p>
   *
   * <p>
   * To find the helper class, this does the following: <br />
   * 1) If the factory class (albeit deprecated) was injected it will be used to get the helper. <br />
   * 2) If the class has been set with a call to {@link #setOpenHelperClass(Class)}, it will be used to construct a
   * helper. <br />
   * 3) If the resource class name is configured in the strings.xml file it will be used. <br />
   * 4) The context class hierarchy is walked looking at the generic parameters for a class extending
   * OrmLiteSqliteOpenHelper. This is used by the {@link OrmLiteBaseActivity} and other base classes. <br />
   * 5) An exception is thrown saying that it was not able to set the helper class.
   * </p>
   */
  public static synchronized OrmLiteSqliteOpenHelper getHelper(Context context) {
    if (helper == null) {
      if (context == null) {
        throw new IllegalArgumentException("context argument is null");
      }
      if (wasClosed) {
        // this can happen if you are calling get/release and then get again
        logger.info("helper has already been closed and is being re-opened.");
      }
      Context appContext = context.getApplicationContext();
      if (factory == null) {
        if (helperClass == null) {
          innerSetHelperClass(lookupHelperClass(appContext, context.getClass()));
        }
        helper = constructHelper(helperClass, appContext);
      } else {
        helper = factory.getHelper(appContext);
      }
      // Log.d(LOG_NAME, "Zero instances.  Created helper.");
      instanceCount = 0;
    }

    instanceCount++;
    // Log.d(LOG_NAME, "helper instance count: " + instC);
    return helper;
  }
  /**
   * Like {@link #getHelper(Context)} but sets the helper class beforehand.
   */
  public static OrmLiteSqliteOpenHelper getHelper(Context context,
      Class<? extends OrmLiteSqliteOpenHelper> openHelperClass) {
    if (helper == null) {
      innerSetHelperClass(openHelperClass);
    }
    return getHelper(context);
  }

  /**
   * @deprecated This has been renamed to be {@link #releaseHelper()}.
   */
  @Deprecated
  public static void release() {
    releaseHelper();
  }

  /**
   * Release the helper that was previously returned by a call {@link #getHelper(Context)} or
   * {@link #getHelper(Context, Class)}. This will decrement the usage counter and close the helper if the counter is
   * 0.
   *
   * <p>
   * <b> WARNING: </b> This should be called in an onDestroy() type of method when your application or service is
   * terminating or if your code is no longer going to use the helper or derived DAOs in any way. _Don't_ call this
   * method if you expect to call {@link #getHelper(Context)} again before the application terminates.
   * </p>
   */
  public static synchronized void releaseHelper() {
    instanceCount--;
    // Log.d(LOG_NAME, "helper instance count: " + instanceCount);
    if (instanceCount == 0) {
      if (helper != null) {
        // Log.d(LOG_NAME, "Zero instances.  Closing helper.");
        helper.close();
        helper = null;
        wasClosed = true;
      }
    } else if (instanceCount < 0) {
      throw new IllegalStateException("Too many calls to release helper.  Instance count = " + instanceCount);
    }
  }

  /**
   * Set the helper class and make sure we aren't changing it to another class.
   */
  private static void innerSetHelperClass(Class<? extends OrmLiteSqliteOpenHelper> openHelperClass) {
    // make sure if that there are not 2 helper classes in an application
    if (helperClass == null) {
      helperClass = openHelperClass;
    } else if (helperClass != openHelperClass) {
      throw new IllegalStateException("Helper class was " + helperClass + " but is trying to be reset to "
          + openHelperClass);
    }
  }

  /**
   * Call the constructor on our helper class.
   */
  private static OrmLiteSqliteOpenHelper constructHelper(Class<? extends OrmLiteSqliteOpenHelper> openHelperClass,
      Context context) {
    Constructor<?> constructor;
    try {
      constructor = openHelperClass.getConstructor(Context.class);
    } catch (Exception e) {
      throw new IllegalStateException("Could not find constructor that takes a Context argument for "
          + openHelperClass, e);
    }
    try {
      return (OrmLiteSqliteOpenHelper) constructor.newInstance(context);
    } catch (Exception e) {
      throw new IllegalStateException("Could not construct instance of helper class " + openHelperClass, e);
    }
  }

  /**
   * Lookup the helper class either from the resource string or by looking for a generic parameter.
   */
  private static Class<? extends OrmLiteSqliteOpenHelper> lookupHelperClass(Context context, Class<?> componentClass) {

    // see if we have the magic resource class name set
    int resourceId =
        context.getResources().getIdentifier(HELPER_CLASS_RESOURCE_NAME, "string", context.getPackageName());
    if (resourceId != 0) {
      String className = context.getResources().getString(resourceId);
      try {
        @SuppressWarnings("unchecked")
        Class<? extends OrmLiteSqliteOpenHelper> castClass =
            (Class<? extends OrmLiteSqliteOpenHelper>) Class.forName(className);
        return castClass;
      } catch (Exception e) {
        throw new IllegalStateException("Could not create helper instance for class " + className, e);
      }
    }

    // try walking the context class to see if we can get the OrmLiteSqliteOpenHelper from a generic parameter
    for (; componentClass != null; componentClass = componentClass.getSuperclass()) {
      Type superType = componentClass.getGenericSuperclass();
      if (superType == null || !(superType instanceof ParameterizedType)) {
        continue;
      }
      // get the generic type arguments
      Type[] types = ((ParameterizedType) superType).getActualTypeArguments();
      // defense
      if (types == null || types.length == 0) {
        continue;
      }
      for (Type type : types) {
        // defense
        if (!(type instanceof Class)) {
          continue;
        }
        Class<?> clazz = (Class<?>) type;
        if (OrmLiteSqliteOpenHelper.class.isAssignableFrom(clazz)) {
          @SuppressWarnings("unchecked")
          Class<? extends OrmLiteSqliteOpenHelper> castOpenHelperClass =
              (Class<? extends OrmLiteSqliteOpenHelper>) clazz;
          return castOpenHelperClass;
        }
      }
    }
    throw new IllegalStateException(
        "Could not find OpenHelperClass because none of its generic parameters extends OrmLiteSqliteOpenHelper: "
            + componentClass);
  }

  /**
   * Factory for providing open helpers.
   *
   * @deprecated We are using other mechanisms now to inject the helper class. See
   *             {@link OpenHelperManager#getHelper(Context)}.
   */
  @Deprecated
  public interface SqliteOpenHelperFactory {

    /**
     * Create and return an open helper associated with the context.
     */
    public OrmLiteSqliteOpenHelper getHelper(Context context);
  }
}
TOP

Related Classes of com.j256.ormlite.android.apptools.OpenHelperManager$SqliteOpenHelperFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.