bwLehrpool Masterserver
Manages authentication and sharing of virtual machines between participating institutions
Database.java
Go to the documentation of this file.
1 package org.openslx.imagemaster.db;
2 
3 import java.io.BufferedInputStream;
4 import java.io.FileInputStream;
5 import java.io.FileNotFoundException;
6 import java.io.IOException;
7 import java.sql.Connection;
8 import java.sql.DriverManager;
9 import java.sql.ResultSet;
10 import java.sql.SQLException;
11 import java.util.Collections;
12 import java.util.Properties;
13 import java.util.Queue;
14 import java.util.Set;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.concurrent.ConcurrentLinkedQueue;
17 
18 import org.apache.logging.log4j.LogManager;
19 import org.apache.logging.log4j.Logger;
21 
22 public class Database
23 {
24 
25  private static final Logger LOGGER = LogManager.getLogger( Database.class );
29  private static final Queue<MysqlConnection> pool = new ConcurrentLinkedQueue<>();
30 
34  private static final Set<MysqlConnection> busyConnections = Collections.newSetFromMap( new ConcurrentHashMap<MysqlConnection, Boolean>() );
35 
36  private static final String host;
37  private static final String dbname;
38  private static final String user;
39  private static final String password;
40 
47  static {
48  // Load connection info from class (TODO: Make pretty)
49  Properties properties = new Properties();
50  try {
51  final BufferedInputStream stream = new BufferedInputStream(
52  new FileInputStream(
53  "config/mysql.properties" ) );
54  properties.load( stream );
55  stream.close();
56  } catch ( FileNotFoundException e ) {
57  LOGGER.fatal( "config/mysql.properties not found!" );
58  System.exit( 1 );
59  } catch ( IOException e ) {
60  LOGGER.fatal( "Error reading from config/mysql.properties: " + e.getMessage() );
61  System.exit( 1 );
62  } catch ( Exception e ) {
63  LOGGER.fatal( "Generic error loading mysql properties file." );
64  e.printStackTrace();
65  System.exit( 1 );
66  }
67  host = properties.getProperty( "host" );
68  dbname = properties.getProperty( "db" );
69  user = properties.getProperty( "user" );
70  password = properties.getProperty( "password" );
71 
72  Util.notNullFatal( host, "host not set in mysql properties" );
73  Util.notNullFatal( dbname, "db not set in mysql properties" );
74  Util.notNullFatal( user, "user not set in mysql properties" );
75  Util.notNullFatal( password, "password not set in mysql properties" );
76 
77  try {
78  Class.forName( "org.mariadb.jdbc.Driver" ).newInstance();
79  } catch ( Exception e1 ) {
80  LOGGER.fatal( "Cannot get mysql JDBC driver", e1 );
81  System.exit( 1 );
82  }
83  }
84 
93  {
94  MysqlConnection con;
95  for ( ;; ) {
96  con = pool.poll();
97  if ( con == null )
98  break;
99  if ( !con.isValid() ) {
100  con.release();
101  continue;
102  }
103  if ( !busyConnections.add( con ) )
104  throw new RuntimeException( "Tried to hand out a busy connection!" );
105  try {
106  // By convention in our program we don't want auto commit
107  con.setAutoCommit( false );
108  return con;
109  } catch ( SQLException e ) {
110  con.release();
111  continue;
112  }
113  }
114  // No pooled connection
115  if ( busyConnections.size() > 20 ) {
116  LOGGER.warn( "Too many open MySQL connections. Possible connection leak!" );
117  return null;
118  }
119  try {
120  // Create fresh connection
121  String uri = "jdbc:mariadb://" + host + "/" + dbname
122  + "?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC"
123  + "&characterSetResults=utf8&connectionCollation=utf8mb4_unicode_ci";
124  Connection rawConnection = DriverManager.getConnection( uri,
125  user, password );
126  // By convention in our program we don't want auto commit
127  rawConnection.setAutoCommit( false );
128  // Wrap into our proxy
129  con = new MysqlConnection( rawConnection );
130  // Keep track of busy mysql connection
131  if ( !busyConnections.add( con ) )
132  throw new RuntimeException( "Tried to hand out a busy connection!" );
133  return con;
134  } catch ( SQLException e ) {
135  LOGGER.info( "Failed to connect to local mysql server", e );
136  }
137  return null;
138  }
139 
147  static void returnConnection( MysqlConnection connection )
148  {
149  if ( !busyConnections.remove( connection ) )
150  throw new RuntimeException( "Tried to return a mysql connection to the pool that was not taken!" );
151  pool.add( connection );
152  }
153 
154  public static void printCharsetInformation()
155  {
156  LOGGER.info( "MySQL charset related variables:" );
157  try ( MysqlConnection connection = Database.getConnection() ) {
158  MysqlStatement stmt = connection.prepareStatement( "SHOW VARIABLES LIKE :what" );
159  stmt.setString( "what", "char%" );
160  ResultSet rs = stmt.executeQuery();
161  while ( rs.next() ) {
162  LOGGER.info( rs.getString( "Variable_name" ) + ": " + rs.getString( "Value" ) );
163  }
164  stmt.setString( "what", "collat%" );
165  rs = stmt.executeQuery();
166  while ( rs.next() ) {
167  LOGGER.info( rs.getString( "Variable_name" ) + ": " + rs.getString( "Value" ) );
168  }
169  } catch ( SQLException e ) {
170  LOGGER.error( "Query failed in Database.printCharsetInformation()", e );
171  }
172  LOGGER.info( "End of variables" );
173  }
174 
175  public static void printDebug()
176  {
177  LOGGER.info( "Available: " + pool.size() );
178  LOGGER.info( "Busy: " + busyConnections.size() );
179  }
180 
181  public static boolean isDuplicateKeyException( SQLException e )
182  {
183  return e != null && e.getErrorCode() == 1062;
184  }
185 
186 }// end class
static boolean isDuplicateKeyException(SQLException e)
Definition: Database.java:181
static final String password
Definition: Database.java:39
static final Set< MysqlConnection > busyConnections
Set of connections currently handed out.
Definition: Database.java:34
static MysqlConnection getConnection()
Get a connection to the database.
Definition: Database.java:92
ResultSet executeQuery()
Executes the statement, which must be a query.
void setString(String name, String value)
Sets a parameter.
static void returnConnection(MysqlConnection connection)
Called by a MysqlConnection when its close()-method is called, so the connection will be added to the...
Definition: Database.java:147
Class for creating PreparedStatements with named parameters.
Some utilities to make our lives easier.
Definition: Util.java:18
static void notNullFatal(Object something, String message)
Check if the given object is null, abort program if true.
Definition: Util.java:36
static final Queue< MysqlConnection > pool
Pool of available connections.
Definition: Database.java:29