view src/nabble/model/Db.java @ 0:7ecd1a4ef557

add content
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 21 Mar 2019 19:15:52 -0600
parents
children
line wrap: on
line source

/*

Copyright (C) 2003  Franklin Schmidt <frank@gustos.com>

*/

package nabble.model;

import fschmidt.db.DbArcana;
import fschmidt.db.DbDatabase;
import fschmidt.db.DbFinder;
import fschmidt.db.util.WeakCacheMap;
import fschmidt.util.java.Computable;
import fschmidt.util.java.SimpleCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;


public final class Db {
	private static final Logger logger = LoggerFactory.getLogger(Db.class);
	static final String url = (String)Init.get("dbUrl");
	static final String user = (String)Init.get("dbUser");
	static final String password = (String)Init.get("dbPassword");
	private static final long idleTimeout = Init.get("idleTimeout",5*60*1000L);

	static final String completeUrl = url + "?user=" + user + "&password=" + password;

	private static final DbDatabase baseDb = DbFinder.getBaseDatabase(url,user,password);
	private static final fschmidt.db.pool.Pool pool = new fschmidt.db.pool.Pool();
	static {
		pool.setIdleTimeout(idleTimeout);
	}

	private static final class NoUserException extends SQLException {
		NoUserException(SQLException e) {
			super(e);
		}
	}

	static Connection getNativeConnection() {
		return pool.getNativeConnection();
	}

	static void checkUser(String user) {
		try {
			Connection con = baseDb.getConnection();
			Statement stmt = con.createStatement();
			try {
				stmt.executeUpdate(
					"set role " + user
				);
			} catch(SQLException e) {
				stmt.executeUpdate(
					"create user " + user + " with password '" + password + "'"
				);
				stmt.executeUpdate(
					"set role " + user
				);
			}
			stmt.close();
			con.close();
		} catch(SQLException e) {
			throw new RuntimeException("check user failed for: "+user,e);
		}
	}

	static class NoSchema extends RuntimeException {
		private NoSchema(String msg) {
			super(msg);
		}
	}

	private static void checkSchema(String schema) {
		try {
			Connection con = dbPostgres.getConnection();
			Statement stmt = con.createStatement();
			try {
				stmt.executeQuery(
					"select * from "+schema+".version"
				);
			} catch(SQLException e) {
				if( e.getMessage().contains("does not exist") )
					throw new NoSchema(schema);
				throw e;
			} finally {
				stmt.close();
				con.close();
			}
		} catch(SQLException e) {
			throw new RuntimeException("check schema failed for: "+schema,e);
		}
	}

	static DbDatabase pooledDb(String user) {
		return new fschmidt.db.pool.DbDatabaseImpl(baseDb,pool,user);
	}

	private static DbDatabase getDb(String user) {
		DbDatabase pooledDb = pooledDb(user);
		DbDatabase db = new fschmidt.db.cache.DbDatabaseImpl(pooledDb);
		if( !user.equals(Db.user) ) {
			checkSchema(user);
			try {
				DbSiteUpdater.update(user,db);
			} catch(UpdatingException e) {
				throw e;
			} catch(RuntimeException e) {
				throw new RuntimeException("couldn't update db for: "+user,e);
			} catch(SQLException e) {
				throw new RuntimeException("couldn't update db for: "+user,e);
			}
		}
		return db;
	}

	private static final DbDatabase dbPostgres = getDb(user);
	public static final DbArcana arcana = dbPostgres.arcana();

	private static SimpleCache<String,DbDatabase> cache = new SimpleCache<String,DbDatabase>(new WeakCacheMap<String,DbDatabase>(), new Computable<String,DbDatabase>() {
		public DbDatabase get(String user) {
			return getDb(user);
		}
	});

	static void uncache(String user) {
		cache.remove(user);
	}

	static DbDatabase db(String user) {
		return cache.get(user);
	}

	public static DbDatabase dbPostgres() {
		return dbPostgres;
	}

	public static DbDatabase dbGlobal() {
		return db("global");
	}

	public static void clearCache() {
		fschmidt.db.cache.DbDatabaseImpl.clearCache();
	}


	public static void main(String[] args) throws Exception {
		Connection con = dbPostgres.getConnection();
		Statement stmt = con.createStatement();
		for( String arg : args ) {
			stmt.executeUpdate(arg);
		}
		stmt.close();
		con.close();
	}

	private Db() {}  // never
}