`
yuanyu5237
  • 浏览: 160145 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

h2 database源码分析·(一)

 
阅读更多

先来无事,发现之前下载的h2 database源码还在source insight里放着,就打开看看。

h2 database是一个开源的,用java写的,支持jdbc连接的内存数据库,提供浏览器模式的控制台。

其源码结构(我用的版本是1.3.154)如下(进入到src目录下,src/org/h2/)

Api   

Bnf

Command

Compress

Constant

Constraint

Engine

Expression

Fulltext

Index

Jdbc

Jdbcx

Jmx

Message

Res

Result

Schema

Security

Server

Store

Table

Tools 工具类,其中有数据库的入口Server.main()

Upgrade

Util

Value

driver.java

从main函数开始说起

 

new Server().runTool(args);

 

 调用runTool()方法,在该方法中,会首先设置一些默认启动参数,然后根据传入的args修改这些默认参数,最后按顺序启动webserver,browser,tcpserver和pgserver,典型代码:

 

if (startDefaultServers) {
            tcpStart = true;
            pgStart = true;
            webStart = true;
            browserStart = true;
}
/*-----------------------------------*/
try {
            if (webStart) {
                web = createWebServer(args);
                web.setShutdownHandler(this);
                SQLException result = null;
                try {
                    web.start();
                } catch (Exception e) {
                    result = DbException.toSQLException(e);
                }
                out.println(web.getStatus());
// start browser in any case (even if the server is already running)
// because some people don't look at the output,
// but are wondering why nothing happens
                if (browserStart) {
                    try {
                        openBrowser(web.getURL());
                    } catch (Exception e) {
                        out.println(e.getMessage());
                    }
                }
                if (result != null) {
                    throw result;
                }
            }
            if (tcpStart) {
                tcp = createTcpServer(args);
                tcp.start();
                out.println(tcp.getStatus());
                tcp.setShutdownHandler(this);
            }
            if (pgStart) {
                pg = createPgServer(args);
                pg.start();
                out.println(pg.getStatus());
            }
} catch (SQLException e) {
            stopAll();
            throw e;
}
 

下面分别来看看这3个server和1个browser:

1WebServer

 

public static Server createWebServer(String... args){
        WebServer service = new WebServer();
        Server server = new Server(service, args);
        service.setShutdownHandler(server);
        return server;
}

 2TcpServer

public static Server createTcpServer(String... args) {
        TcpServer service = new TcpServer();
        Server server = new Server(service, args);
        service.setShutdownHandler(server);
        return server;
}

 3PgServer

public static Server createPgServer(String... args){
        return new Server(new PgServer(), args);
}

 3个server都只是创建,要启动server,都需要调用start()方法,在start方法中,调用各自的service类,start各自的server,然后创建单独的线程执行运行该server,若为守护进程,还需要将其设置为守护进程:

public Server start() throws SQLException {
        try {
            started = true;
            service.start();
            Thread t = new Thread(this);
            t.setDaemon(service.isDaemon());
            String name = service.getName() + " (" + service.getURL() + ")";
            t.setName(name);
            t.start();
            for (int i = 1; i < 64; i += i) {
                wait(i);
                if (isRunning(false)) {
                    return this;
                }
            }
            if (isRunning(true)) {
                return this;
            }
            throw DbException.get(ErrorCode.EXCEPTION_OPENING_PORT_2, name, "timeout");
        } catch (DbException e) {
            throw DbException.toSQLException(e);
        }
}

 最后,是openBrowser(),根据指定的URL打开一个浏览器窗口或者标签页。

public static void openBrowser(String url) throws Exception {
        try {
            String osName = SysProperties.getStringSetting("os.name", "linux").toLowerCase();
            Runtime rt = Runtime.getRuntime();
            String browser = System.getProperty(SysProperties.H2_BROWSER);
            if (browser != null) {
                if (browser.startsWith("call:")) {
                    browser = browser.substring("call:".length());
                    Utils.callStaticMethod(browser, url);
                } else if (browser.indexOf("%url") >= 0) {
                    String[] args = StringUtils.arraySplit(browser, ',', false);
                    for (int i = 0; i < args.length; i++) {
                        args[i] = StringUtils.replaceAll(args[i], "%url", url);
                    }
                    rt.exec(args);
                } else if (osName.indexOf("windows") >= 0) {
                    rt.exec(new String[] { "cmd.exe", "/C",  browser, url });
                } else {
                    rt.exec(new String[] { browser, url });
                }
                return;
            }
            try {
                Class<?> desktopClass = Class.forName("java.awt.Desktop");
                // Desktop.isDesktopSupported()
                Boolean supported = (Boolean) desktopClass.
                    getMethod("isDesktopSupported").
                    invoke(null, new Object[0]);
                URI uri = new URI(url);
                if (supported) {
                    // Desktop.getDesktop();
                    Object desktop = desktopClass.getMethod("getDesktop").
                        invoke(null, new Object[0]);
                    // desktop.browse(uri);
                    desktopClass.getMethod("browse", URI.class).
                        invoke(desktop, uri);
                    return;
                }
            } catch (Exception e) {
                // ignore
            }
            if (osName.indexOf("windows") >= 0) {
                rt.exec(new String[] { "rundll32", "url.dll,FileProtocolHandler", url });
            } else if (osName.indexOf("mac") >= 0 || osName.indexOf("darwin") >= 0) {
                // Mac OS: to open a page with Safari, use "open -a Safari"
                Runtime.getRuntime().exec(new String[] { "open", url });
            } else {
                String[] browsers = { "firefox", "mozilla-firefox", "mozilla", "konqueror", "netscape", "opera" };
                boolean ok = false;
                for (String b : browsers) {
                    try {
                        rt.exec(new String[] { b, url });
                        ok = true;
                        break;
                    } catch (Exception e) {
                        // ignore and try the next
                    }
                }
                if (!ok) {
                    // No success in detection.
                    throw new Exception("Browser detection failed and system property " + SysProperties.H2_BROWSER + " not set");
                }
            }
        } catch (Exception e) {
            throw new Exception("Failed to start a browser to open the URL " + url + ": " + e.getMessage());
        }
}

 这段代码其实挺有意思的,就是打开了一个浏览器,参考了这段代码的实现,并阅读了util下的New, Util, StringUtil三个类得部分代码和constant下的SysProperties类,拼凑了下面的一段程序,可直接运行,就能打开浏览器。

 

package org.h2.test;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.util.ArrayList;

public class OpenBrowserTest {

	public static void main(String[] args) throws Exception {
		openBrowser("http://www.baidu.com");
	}

	public static void openBrowser(String url) throws Exception {
        try {
        	String s = System.getProperty("os.name");
            String osName = (s == null ? "linux" : s).toLowerCase();
            Runtime rt = Runtime.getRuntime();
            String browser = System.getProperty("h2.browser");
            if (browser != null) {
                if (browser.startsWith("call:")) {
                    browser = browser.substring("call:".length());
                    callStaticMethod(browser, url);
                } else if (browser.indexOf("%url") >= 0) {
                    String[] args = arraySplit(browser, ',', false);
                    for (int i = 0; i < args.length; i++) {
                        args[i] = replaceAll(args[i], "%url", url);
                    }
                    rt.exec(args);
                } else if (osName.indexOf("windows") >= 0) {
                    rt.exec(new String[] { "cmd.exe", "/C",  browser, url });
                } else {
                    rt.exec(new String[] { browser, url });
                }
                return;
            }
            try {
                Class<?> desktopClass = Class.forName("java.awt.Desktop");
                // Desktop.isDesktopSupported()
                Boolean supported = (Boolean) desktopClass.
                    getMethod("isDesktopSupported").
                    invoke(null, new Object[0]);
                URI uri = new URI(url);
                if (supported) {
                    // Desktop.getDesktop();
                    Object desktop = desktopClass.getMethod("getDesktop").
                        invoke(null, new Object[0]);
                    // desktop.browse(uri);
                    desktopClass.getMethod("browse", URI.class).
                        invoke(desktop, uri);
                    return;
                }
            } catch (Exception e) {
                // ignore
            }
            if (osName.indexOf("windows") >= 0) {
                rt.exec(new String[] { "rundll32", "url.dll,FileProtocolHandler", url });
            } else if (osName.indexOf("mac") >= 0 || osName.indexOf("darwin") >= 0) {
                // Mac OS: to open a page with Safari, use "open -a Safari"
                Runtime.getRuntime().exec(new String[] { "open", url });
            } else {
                String[] browsers = { "firefox", "mozilla-firefox", "mozilla", "konqueror", "netscape", "opera" };
                boolean ok = false;
                for (String b : browsers) {
                    try {
                        rt.exec(new String[] { b, url });
                        ok = true;
                        break;
                    } catch (Exception e) {
                        // ignore and try the next
                    }
                }
                if (!ok) {
                    // No success in detection.
                    throw new Exception("Browser detection failed and system property " + "h2.browser" + " not set");
                }
            }
        } catch (Exception e) {
            throw new Exception("Failed to start a browser to open the URL " + url + ": " + e.getMessage());
        }
    }
	
	public static Object callStaticMethod(String classAndMethod, Object... params) throws Exception {
        int lastDot = classAndMethod.lastIndexOf('.');
        String className = classAndMethod.substring(0, lastDot);
        String methodName = classAndMethod.substring(lastDot + 1);
        return classMethodInternal(methodName, Class.forName(className), null, params);
    }
	
	private static Object classMethodInternal(String methodName, Class<?> clazz, Object instance, Object... params) throws Exception {
        Method best = null;
        int bestMatch = 0;
        boolean isStatic = instance == null;
        for (Method m : clazz.getMethods()) {
            if (Modifier.isStatic(m.getModifiers()) == isStatic && m.getName().equals(methodName)) {
                int p = match(m.getParameterTypes(), params);
                if (p > bestMatch) {
                    bestMatch = p;
                    best = m;
                }
            }
        }
        if (best == null) {
            throw new NoSuchMethodException(methodName);
        }
        return best.invoke(instance, params);
    }
	
	private static int match(Class<?>[] params, Object[] values) {
        int len = params.length;
        if (len == values.length) {
            int points = 1;
            for (int i = 0; i < len; i++) {
                Class<?> pc = getNonPrimitiveClass(params[i]);
                Class<?> vc = values[i].getClass();
                if (pc == vc) {
                    points++;
                } else if (!pc.isAssignableFrom(vc)) {
                    return 0;
                }
            }
            return points;
        }
        return 0;
    }
	
	public static Class<?> getNonPrimitiveClass(Class<?> clazz) {
        if (!clazz.isPrimitive()) {
            return clazz;
        } else if (clazz == boolean.class) {
            return Boolean.class;
        } else if (clazz == byte.class) {
            return Byte.class;
        } else if (clazz == char.class) {
            return Character.class;
        } else if (clazz == double.class) {
            return Double.class;
        } else if (clazz == float.class) {
            return Float.class;
        } else if (clazz == int.class) {
            return Integer.class;
        } else if (clazz == long.class) {
            return Long.class;
        } else if (clazz == short.class) {
            return Short.class;
        } else if (clazz == void.class) {
            return Void.class;
        }
        return clazz;
    }
	
	public static String[] arraySplit(String s, char separatorChar, boolean trim) {
        if (s == null) {
            return null;
        }
        int length = s.length();
        if (length == 0) {
            return new String[0];
        }
        ArrayList<String> list = new ArrayList<String>();
        StringBuilder buff = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            char c = s.charAt(i);
            if (c == separatorChar) {
                String e = buff.toString();
                list.add(trim ? e.trim() : e);
                buff.setLength(0);
            } else if (c == '\\' && i < length - 1) {
                buff.append(s.charAt(++i));
            } else {
                buff.append(c);
            }
        }
        String e = buff.toString();
        list.add(trim ? e.trim() : e);
        String[] array = new String[list.size()];
        list.toArray(array);
        return array;
    }
	
	public static String replaceAll(String s, String before, String after) {
        int next = s.indexOf(before);
        if (next < 0) {
            return s;
        }
        StringBuilder buff = new StringBuilder(s.length() - before.length() + after.length());
        int index = 0;
        while (true) {
            buff.append(s.substring(index, next)).append(after);
            index = next + before.length();
            next = s.indexOf(before, index);
            if (next < 0) {
                buff.append(s.substring(index));
                break;
            }
        }
        return buff.toString();
    }
}
 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics