001package runwar.mariadb4j;
002
003import java.io.File;
004import java.io.FileInputStream;
005import java.io.IOException;
006import java.io.InputStream;
007import java.net.URLClassLoader;
008import java.nio.file.Files;
009import runwar.logging.Logger;
010import static runwar.util.Reflection.invoke;
011import static runwar.util.Reflection.method;
012import static runwar.util.Reflection.load;
013
014public class MariaDB4jManager {
015
016    private File baseDir;
017    private File dataDir;
018    private Object server;
019    private String username, password, dbName = null;
020    private int port;
021    private URLClassLoader classLoader;
022    private static Logger log = Logger.getLogger("RunwarLogger");
023    volatile boolean isShuttingDown;
024
025    public MariaDB4jManager(URLClassLoader _classLoader) {
026        classLoader = _classLoader;
027    }
028
029    public boolean canLoad() {
030        try {
031            log.debug("Checking for MariaDB4j class avaiability");
032            load(classLoader, "ch.vorburger.mariadb4j.DBConfigurationBuilder");
033            return true;
034        } catch (Exception e) {
035            log.debug("MariaDB4j classes are not available");
036            return false;
037        }
038    }
039
040    public void start(int port, File baseDirectory, File dataDirectory, File importSQLFile) throws IOException {
041        this.port = port;
042        System.out.println("Starting MariaDB server on port " + port);
043        if (baseDirectory == null) {
044            baseDir = Files.createTempDirectory("mariadb4j").toFile();
045        } else {
046            baseDir = baseDirectory;
047        }
048        System.out.println("MariaDB4j base directory " + baseDir.getAbsolutePath());
049        if (dataDirectory == null) {
050            dataDir = new File(baseDir.getAbsolutePath(), "data-dir");
051        } else {
052            dataDir = dataDirectory;
053        }
054        System.out.println("MariaDB4j datadirectory " + dataDir.getAbsolutePath());
055
056        Class<?> builderClass = load(classLoader, "ch.vorburger.mariadb4j.DBConfigurationBuilder");
057        if (builderClass == null) {
058            throw new RuntimeException("COULD NOT LOAD DB CLASS");
059        }
060        Object builder = invoke(method(builderClass, "newBuilder"), null);
061
062        invoke(method(builderClass, "setPort", int.class), builder, port);
063        invoke(method(builderClass, "setBaseDir", String.class), builder, baseDir.getAbsolutePath());
064        invoke(method(builderClass, "setDataDir", String.class), builder, dataDir.getAbsolutePath());
065
066        Class<?> DBClass = load(classLoader, "ch.vorburger.mariadb4j.DB");
067        ClassLoader OCL = Thread.currentThread().getContextClassLoader();
068        try {
069            Thread.currentThread().setContextClassLoader(classLoader);
070            server = invoke(
071                    method(DBClass, "newEmbeddedDB", load(classLoader, "ch.vorburger.mariadb4j.DBConfiguration")),
072                    DBClass, method(builderClass, "build").invoke(builder));
073            invoke(method(server.getClass(), "start"), server);
074            System.out.println("Started MariaDB4j server");
075            if (importSQLFile != null) {
076                if (importSQLFile.exists()) {
077                    // source(String resource, String username, String password,
078                    // String dbName)
079                    System.out.println("importing SQL file: " + importSQLFile.getAbsolutePath());
080                    run(importSQLFile, username, password, dbName);
081                } else {
082                    log.error("Could not load MariaDB4j SQL file, file does not exist: "
083                            + importSQLFile.getAbsolutePath());
084                    System.out.println("Could not load MariaDB4j SQL file, file does not exist: : "
085                            + importSQLFile.getAbsolutePath());
086                }
087            }
088
089        } catch (Exception e) {
090            e.printStackTrace();
091        } finally {
092            Thread.currentThread().setContextClassLoader(OCL);
093        }
094        isShuttingDown = false;
095        // INSTANCE = this;
096        // final Thread mainThread = Thread.currentThread();
097        // Runtime.getRuntime().addShutdownHook(new Thread() {
098        // public void run() {
099        // try {
100        // if(!isShuttingDown)
101        // INSTANCE.stop();
102        // mainThread.join();
103        // } catch ( Exception e) {
104        // e.printStackTrace();
105        // }
106        // }
107        // });
108
109    }
110
111    public void run(File file, String username, String password, String dbName) throws IOException {
112        FileInputStream from = new FileInputStream(file);
113        // run("source " + file.getAbsolutePath(), username, password, dbName);
114        run("[MariaDB4j] importing " + file.getAbsolutePath(), from, username, password, dbName);
115    }
116
117    public void createDB(String dbName) throws IOException {
118        ClassLoader OCL = Thread.currentThread().getContextClassLoader();
119        try {
120            invoke(method(server.getClass(), "createDB", String.class), server, dbName);
121        } catch (Exception e) {
122            e.printStackTrace();
123        } finally {
124            Thread.currentThread().setContextClassLoader(OCL);
125        }
126    }
127
128    public void run(String logInfoText, InputStream fromIS, String username, String password, String dbName)
129            throws IOException {
130        ClassLoader OCL = Thread.currentThread().getContextClassLoader();
131        try {
132            java.lang.reflect.Method runMethod = method(server.getClass(), "run", String.class, InputStream.class,
133                    String.class, String.class, String.class);
134            // dirty hack so we don't have to pass in a potentially huge string
135            runMethod.setAccessible(true);
136            invoke(runMethod, server, logInfoText, fromIS, username, password, dbName);
137        } catch (Exception e) {
138            try {
139                // this will print out the SQL exception if the problem was
140                // there
141                System.out.println("[MariaDB4j] Error running SQL: ");
142                System.out.print("    ");
143                System.out.println(e.getCause().getCause().getMessage());
144            } catch (Exception e2) {
145                e.printStackTrace();
146            }
147        } finally {
148            if (fromIS != null) {
149                fromIS.close();
150            }
151            Thread.currentThread().setContextClassLoader(OCL);
152        }
153    }
154
155    public void run(String command, String username, String password, String dbName) {
156        System.out.println("[MariaDB4j] Running SQL command: " + command);
157        ClassLoader OCL = Thread.currentThread().getContextClassLoader();
158        try {
159            invoke(method(server.getClass(), "run", String.class, String.class, String.class, String.class), server,
160                    command, username, password, dbName);
161        } catch (Exception e) {
162            e.printStackTrace();
163        } finally {
164            Thread.currentThread().setContextClassLoader(OCL);
165        }
166    }
167
168    public void stop() throws InterruptedException {
169        isShuttingDown = true;
170        System.out.println("*** Stopping MariaDB server on port " + port + " ...");
171        try {
172            invoke(method(server.getClass(), "stop"), server);
173            System.out.println("*** Stopped MariaDB server on port " + port);
174        } catch (Exception e) {
175            System.out.println("*** Error stopping MariaDB server on port " + port);
176            e.printStackTrace();
177        }
178    }
179
180    public String getUsername() {
181        return username;
182    }
183
184    public void setUsername(String username) {
185        this.username = username;
186    }
187
188    public String getPassword() {
189        return password;
190    }
191
192    public void setPassword(String password) {
193        this.password = password;
194    }
195
196    public String getDbName() {
197        return dbName;
198    }
199
200    public void setDbName(String dbName) {
201        this.dbName = dbName;
202    }
203
204}