diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/nabble/model/Db.java	Thu Mar 21 19:15:52 2019 -0600
@@ -0,0 +1,164 @@
+/*
+
+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
+}