class DaoManager {

	public synchronized static <D extends Dao<T, ?>, T> D createDao(ConnectionSource connectionSource, Class<T> clazz)
			throws SQLException {
		if (connectionSource == null) {
			throw new IllegalArgumentException("connectionSource argument cannot be null");
		}
		ClassConnectionSource key = new ClassConnectionSource(connectionSource, clazz);
		Dao<?, ?> dao = lookupDao(key);
		if (dao != null) {
			@SuppressWarnings("unchecked")
			D castDao = (D) dao;
			return castDao;
		}

		// see if we can build it from source
		dao = createDaoFromConfig(connectionSource, clazz);
		if (dao != null) {
			@SuppressWarnings("unchecked")
			D castDao = (D) dao;
			return castDao;
		}

		DatabaseTable databaseTable = clazz.getAnnotation(DatabaseTable.class);
		if (databaseTable == null || databaseTable.daoClass() == Void.class
				|| databaseTable.daoClass() == BaseDaoImpl.class) {
			// see if the database type has some special table config extract method (Android)
			DatabaseType databaseType = connectionSource.getDatabaseType();
			DatabaseTableConfig<T> config = databaseType.extractDatabaseTableConfig(connectionSource, clazz);
			Dao<T, ?> daoTmp;
			if (config == null) {
				daoTmp = BaseDaoImpl.createDao(connectionSource, clazz);
			} else {
				daoTmp = BaseDaoImpl.createDao(connectionSource, config);
			}
			dao = daoTmp;
			logger.debug("created dao for class {} with reflection", clazz);
		} else {
			Class<?> daoClass = databaseTable.daoClass();
			Object[] arguments = new Object[] { connectionSource, clazz };
			// look first for the constructor with a class parameter in case it is a generic dao
			Constructor<?> daoConstructor = findConstructor(daoClass, arguments);
			if (daoConstructor == null) {
				// then look for the constructor with just the ConnectionSource
				arguments = new Object[] { connectionSource };
				daoConstructor = findConstructor(daoClass, arguments);
				if (daoConstructor == null) {
					throw new SQLException(
							"Could not find public constructor with ConnectionSource and optional Class parameters "
									+ daoClass + ".  Missing static on class?");
				}
			}
			try {
				dao = (Dao<?, ?>) daoConstructor.newInstance(arguments);
				logger.debug("created dao for class {} from constructor", clazz);
			} catch (Exception e) {
				throw SqlExceptionUtil.create("Could not call the constructor in class " + daoClass, e);
			}
		}

		registerDao(connectionSource, dao);
		@SuppressWarnings("unchecked")
		D castDao = (D) dao;
		return castDao;
	}

}