JR Utily

simplify H2 console, and deploy it only when in Integration project stage

package org.legrog.util;
// Code copied from org.h2.server.web.ConnectionInfo
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
//package org.h2.server.web;
import org.h2.util.MathUtils;
import org.h2.util.StringUtils;
/**
* The connection info object is a wrapper for database connection information
* such as the database URL, user name and password.
* This class is used by the H2 Console.
*/
public class ConnectionInfo implements Comparable<ConnectionInfo> {
/**
* The driver class name.
*/
public String driver;
/**
* The database URL.
*/
public String url;
/**
* The user name.
*/
public String user;
/**
* The connection display name.
*/
String name;
/**
* The last time this connection was used.
*/
int lastAccess;
ConnectionInfo() {
// nothing to do
}
public ConnectionInfo(String data) {
String[] array = StringUtils.arraySplit(data, '|', false);
name = get(array, 0);
driver = get(array, 1);
url = get(array, 2);
user = get(array, 3);
}
private static String get(String[] array, int i) {
return array != null && array.length > i ? array[i] : "";
}
String getString() {
return StringUtils.arrayCombine(new String[] { name, driver, url, user }, '|');
}
@Override
public int compareTo(ConnectionInfo o) {
return -MathUtils.compareInt(lastAccess, o.lastAccess);
}
}
\ No newline at end of file
package org.legrog.util;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.deltaspike.core.api.projectstage.ProjectStage;
import org.apache.deltaspike.core.util.ProjectStageProducer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.ServletConfig;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import org.h2.engine.Constants;
import org.h2.server.web.PageParser;
import org.h2.util.New;
import static org.legrog.util.H2ConsoleServlet.CONSOLE_MAPPING;
@WebServlet(urlPatterns="/console/*", name="H2Console", loadOnStartup=1)
public class H2ConsoleServlet extends HttpServlet {
// Code copied from org.h2.server.web.WebServlet
private static final long serialVersionUID = 1L;
private transient WebServer server;
@WebServlet(
urlPatterns = CONSOLE_MAPPING,
name = "H2Console",
loadOnStartup = 1,
initParams = {@WebInitParam(name = "webAllowOthers", value = ""), @WebInitParam(name = "trace", value = "")}
)
public class H2ConsoleServlet extends org.h2.server.web.WebServlet {
static final String CONSOLE_MAPPING = "/console/*";
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void init() {
ServletConfig config = getServletConfig();
Enumeration<?> en = config.getInitParameterNames();
ArrayList<String> list = New.arrayList();
while (en.hasMoreElements()) {
String name = en.nextElement().toString();
String value = config.getInitParameter(name);
if (!name.startsWith("-")) {
name = "-" + name;
}
list.add(name);
if (value.length() > 0) {
list.add(value);
}
}
String[] args = new String[list.size()];
list.toArray(args);
server = new WebServer();
server.setAllowChunked(false);
server.init(args);
}
@Override
public void destroy() {
server.stop();
}
private boolean allow(HttpServletRequest req) {
if (server.getAllowOthers()) {
return true;
}
String addr = req.getRemoteAddr();
try {
InetAddress address = InetAddress.getByName(addr);
return address.isLoopbackAddress();
} catch (UnknownHostException e) {
return false;
} catch (NoClassDefFoundError e) {
// Google App Engine does not allow java.net.InetAddress
return false;
}
}
private String getAllowedFile(HttpServletRequest req, String requestedFile) {
if (!allow(req)) {
return "notAllowed.jsp";
}
if (requestedFile.length() == 0) {
return "index.do";
}
return requestedFile;
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
req.setCharacterEncoding("utf-8");
String file = req.getPathInfo();
if (file == null) {
resp.sendRedirect(req.getRequestURI() + "/");
return;
} else if (file.startsWith("/")) {
file = file.substring(1);
}
file = getAllowedFile(req, file);
// extract the request attributes
Properties attributes = new Properties();
Enumeration<?> en = req.getAttributeNames();
while (en.hasMoreElements()) {
String name = en.nextElement().toString();
String value = req.getAttribute(name).toString();
attributes.put(name, value);
}
en = req.getParameterNames();
while (en.hasMoreElements()) {
String name = en.nextElement().toString();
String value = req.getParameter(name);
attributes.put(name, value);
}
WebSession session = null;
String sessionId = attributes.getProperty("jsessionid");
if (sessionId != null) {
session = server.getSession(sessionId);
}
WebApp app = new WebApp(server);
app.setSession(session, attributes);
String ifModifiedSince = req.getHeader("if-modified-since");
String hostAddr = req.getRemoteAddr();
file = app.processRequest(file, hostAddr);
session = app.getSession();
String mimeType = app.getMimeType();
boolean cache = app.getCache();
if (cache && server.getStartDateTime().equals(ifModifiedSince)) {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return;
}
byte[] bytes = server.getFile(file);
if (bytes == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND);
bytes = ("File not found: " + file).getBytes(Constants.UTF8);
ProjectStage projectStage = ProjectStageProducer.getInstance().getProjectStage();
if (projectStage == ProjectStage.IntegrationTest) {
logger.info("Create a H2 Console Servlet mapped to {}", CONSOLE_MAPPING);
super.init();
} else {
if (session != null && file.endsWith(".jsp")) {
String page = new String(bytes, Constants.UTF8);
page = PageParser.parse(page, session.map);
bytes = page.getBytes(Constants.UTF8);
}
resp.setContentType(mimeType);
if (!cache) {
resp.setHeader("Cache-Control", "no-cache");
} else {
resp.setHeader("Cache-Control", "max-age=10");
resp.setHeader("Last-Modified", server.getStartDateTime());
}
}
if (bytes != null) {
ServletOutputStream out = resp.getOutputStream();
out.write(bytes);
}
logger.info("Skipping H2 Console Servlet creation");
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
doGet(req, resp);
}
}
......
package org.legrog.util;
// Code copied from org.h2.server.web.PageParser
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
//package org.h2.server.web;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.h2.util.New;
/**
* A page parser can parse an HTML page and replace the tags there.
* This class is used by the H2 Console.
*/
public class PageParser {
private static final int TAB_WIDTH = 4;
private final String page;
private int pos;
private final Map<String, Object> settings;
private final int len;
private StringBuilder result;
private PageParser(String page, Map<String, Object> settings, int pos) {
this.page = page;
this.pos = pos;
this.len = page.length();
this.settings = settings;
result = new StringBuilder(len);
}
/**
* Replace the tags in the HTML page with the given settings.
*
* @param page the HTML page
* @param settings the settings
* @return the converted page
*/
public static String parse(String page, Map<String, Object> settings) {
PageParser block = new PageParser(page, settings, 0);
return block.replaceTags();
}
private void setError(int i) {
String s = page.substring(0, i) + "####BUG####" + page.substring(i);
s = PageParser.escapeHtml(s);
result = new StringBuilder();
result.append(s);
}
private String parseBlockUntil(String end) throws ParseException {
PageParser block = new PageParser(page, settings, pos);
block.parseAll();
if (!block.readIf(end)) {
throw new ParseException(page, block.pos);
}
pos = block.pos;
return block.result.toString();
}
private String replaceTags() {
try {
parseAll();
if (pos != len) {
setError(pos);
}
} catch (ParseException e) {
setError(pos);
}
return result.toString();
}
@SuppressWarnings("unchecked")
private void parseAll() throws ParseException {
StringBuilder buff = result;
String p = page;
int i = pos;
for (; i < len; i++) {
char c = p.charAt(i);
switch (c) {
case '<': {
if (p.charAt(i + 3) == ':' && p.charAt(i + 1) == '/') {
// end tag
pos = i;
return;
} else if (p.charAt(i + 2) == ':') {
pos = i;
if (readIf("<c:forEach")) {
String var = readParam("var");
String items = readParam("items");
read(">");
int start = pos;
List<Object> list = (List<Object>) get(items);
if (list == null) {
result.append("?items?");
list = New.arrayList();
}
if (list.size() == 0) {
parseBlockUntil("</c:forEach>");
}
for (Object o : list) {
settings.put(var, o);
pos = start;
String block = parseBlockUntil("</c:forEach>");
result.append(block);
}
} else if (readIf("<c:if")) {
String test = readParam("test");
int eq = test.indexOf("=='");
if (eq < 0) {
setError(i);
return;
}
String val = test.substring(eq + 3, test.length() - 1);
test = test.substring(0, eq);
String value = (String) get(test);
read(">");
String block = parseBlockUntil("</c:if>");
pos--;
if (value.equals(val)) {
result.append(block);
}
} else {
setError(i);
return;
}
i = pos;
} else {
buff.append(c);
}
break;
}
case '$':
if (p.length() > i + 1 && p.charAt(i + 1) == '{') {
i += 2;
int j = p.indexOf('}', i);
if (j < 0) {
setError(i);
return;
}
String item = p.substring(i, j).trim();
i = j;
String s = (String) get(item);
replaceTags(s);
} else {
buff.append(c);
}
break;
default:
buff.append(c);
break;
}
}
pos = i;
}
@SuppressWarnings("unchecked")
private Object get(String item) {
int dot = item.indexOf('.');
if (dot >= 0) {
String sub = item.substring(dot + 1);
item = item.substring(0, dot);
HashMap<String, Object> map = (HashMap<String, Object>) settings.get(item);
if (map == null) {
return "?" + item + "?";
}
return map.get(sub);
}
return settings.get(item);
}
private void replaceTags(String s) {
if (s != null) {
result.append(PageParser.parse(s, settings));
}
}
private String readParam(String name) throws ParseException {
read(name);
read("=");
read("\"");
int start = pos;
while (page.charAt(pos) != '"') {
pos++;
}
int end = pos;
read("\"");
String s = page.substring(start, end);
return PageParser.parse(s, settings);
}
private void skipSpaces() {
while (page.charAt(pos) == ' ') {
pos++;
}
}
private void read(String s) throws ParseException {
if (!readIf(s)) {
throw new ParseException(s, pos);
}
}
private boolean readIf(String s) {
skipSpaces();
if (page.regionMatches(pos, s, 0, s.length())) {
pos += s.length();
skipSpaces();
return true;
}
return false;
}
/**
* Convert data to HTML, but don't convert newlines and multiple spaces.
*
* @param s the data
* @return the escaped html text
*/
static String escapeHtmlData(String s) {
return escapeHtml(s, false);
}
/**
* Convert data to HTML, including newlines and multiple spaces.
*
* @param s the data
* @return the escaped html text
*/
public static String escapeHtml(String s) {
return escapeHtml(s, true);
}
private static String escapeHtml(String s, boolean convertBreakAndSpace) {
if (s == null) {
return null;
}
if (convertBreakAndSpace) {
if (s.length() == 0) {
return "&nbsp;";
}
}
StringBuilder buff = new StringBuilder(s.length());
boolean convertSpace = true;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ' ' || c == '\t') {
// convert tabs into spaces
for (int j = 0; j < (c == ' ' ? 1 : TAB_WIDTH); j++) {
if (convertSpace && convertBreakAndSpace) {
buff.append("&nbsp;");
} else {
buff.append(' ');
convertSpace = true;
}
}
continue;
}
convertSpace = false;
switch (c) {
case '$':
// so that ${ } in the text is interpreted correctly
buff.append("&#36;");
break;
case '<':
buff.append("&lt;");
break;
case '>':
buff.append("&gt;");
break;
case '&':
buff.append("&amp;");
break;
case '"':
buff.append("&quot;");
break;
case '\'':
buff.append("&#39;");
break;
case '\n':
if (convertBreakAndSpace) {
buff.append("<br />");
convertSpace = true;
} else {
buff.append(c);
}
break;
default:
if (c >= 128) {
buff.append("&#").append((int) c).append(';');
} else {
buff.append(c);
}
break;
}
}
return buff.toString();
}
/**
* Escape text as a the javascript string.
*
* @param s the text
* @return the javascript string
*/
static String escapeJavaScript(String s) {
if (s == null) {
return null;
}
if (s.length() == 0) {
return "";
}
StringBuilder buff = new StringBuilder(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '"':
buff.append("\\\"");
break;
case '\'':
buff.append("\\'");
break;
case '\\':
buff.append("\\\\");
break;
case '\n':
buff.append("\\n");
break;
case '\r':
buff.append("\\r");
break;
case '\t':
buff.append("\\t");
break;
default:
buff.append(c);
break;
}
}
return buff.toString();
}
}
\ No newline at end of file
package org.legrog.util;
// Code copied from org.h2.server.web.WebApp
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
//package org.h2.server.web;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import org.h2.api.ErrorCode;
import org.h2.bnf.Bnf;
import org.h2.bnf.context.DbColumn;
import org.h2.bnf.context.DbContents;
import org.h2.bnf.context.DbSchema;
import org.h2.bnf.context.DbTableOrView;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.DbException;
import org.h2.security.SHA256;
import org.h2.tools.Backup;
import org.h2.tools.ChangeFileEncryption;
import org.h2.tools.ConvertTraceFile;
import org.h2.tools.CreateCluster;
import org.h2.tools.DeleteDbFiles;
import org.h2.tools.Recover;
import org.h2.tools.Restore;
import org.h2.tools.RunScript;
import org.h2.tools.Script;
import org.h2.tools.SimpleResultSet;
import org.h2.util.JdbcUtils;
import org.h2.util.New;
import org.h2.util.Profiler;
import org.h2.util.ScriptReader;
import org.h2.util.SortedProperties;
import org.h2.util.StatementBuilder;
import org.h2.util.StringUtils;
import org.h2.util.Tool;
import org.h2.util.Utils;
/**
* For each connection to a session, an object of this class is created.
* This class is used by the H2 Console.
*/
public class WebApp {
/**
* The web server.
*/
protected final WebServer server;
/**
* The session.
*/
protected WebSession session;
/**
* The session attributes
*/
protected Properties attributes;
/**
* The mime type of the current response.
*/
protected String mimeType;
/**
* Whether the response can be cached.
*/
protected boolean cache;
/**
* Whether to close the connection.
*/
protected boolean stop;
/**
* The language in the HTTP header.
*/
protected String headerLanguage;
private Profiler profiler;
WebApp(WebServer server) {
this.server = server;
}
/**
* Set the web session and attributes.
*
* @param session the session
* @param attributes the attributes
*/
void setSession(WebSession session, Properties attributes) {
this.session = session;
this.attributes = attributes;
}
/**
* Process an HTTP request.
*
* @param file the file that was requested
* @param hostAddr the host address
* @return the name of the file to return to the client
*/
String processRequest(String file, String hostAddr) {
int index = file.lastIndexOf('.');
String suffix;
if (index >= 0) {
suffix = file.substring(index + 1);
} else {
suffix = "";
}
if ("ico".equals(suffix)) {
mimeType = "image/x-icon";
cache = true;
} else if ("gif".equals(suffix)) {
mimeType = "image/gif";
cache = true;
} else if ("css".equals(suffix)) {
cache = true;
mimeType = "text/css";
} else if ("html".equals(suffix) ||
"do".equals(suffix) ||
"jsp".equals(suffix)) {
cache = false;
mimeType = "text/html";
if (session == null) {
session = server.createNewSession(hostAddr);
if (!"notAllowed.jsp".equals(file)) {
file = "index.do";
}
}
} else if ("js".equals(suffix)) {
cache = true;
mimeType = "text/javascript";
} else {
cache = true;
mimeType = "application/octet-stream";
}
trace("mimeType=" + mimeType);
trace(file);
if (file.endsWith(".do")) {
file = process(file);
}
return file;
}
private static String getComboBox(String[] elements, String selected) {
StringBuilder buff = new StringBuilder();
for (String value : elements) {
buff.append("<option value=\"").
append(PageParser.escapeHtmlData(value)).
append('\"');
if (value.equals(selected)) {
buff.append(" selected");
}
buff.append('>').
append(PageParser.escapeHtml(value)).
append("</option>");
}
return buff.toString();
}
private static String getComboBox(String[][] elements, String selected) {
StringBuilder buff = new StringBuilder();
for (String[] n : elements) {
buff.append("<option value=\"").
append(PageParser.escapeHtmlData(n[0])).
append('\"');
if (n[0].equals(selected)) {
buff.append(" selected");
}
buff.append('>').
append(PageParser.escapeHtml(n[1])).
append("</option>");
}
return buff.toString();
}
private String process(String file) {
trace("process " + file);
while (file.endsWith(".do")) {
if ("login.do".equals(file)) {
file = login();
} else if ("index.do".equals(file)) {
file = index();
} else if ("logout.do".equals(file)) {
file = logout();
} else if ("settingRemove.do".equals(file)) {
file = settingRemove();
} else if ("settingSave.do".equals(file)) {
file = settingSave();
} else if ("test.do".equals(file)) {
file = test();
} else if ("query.do".equals(file)) {
file = query();
} else if ("tables.do".equals(file)) {
file = tables();
} else if ("editResult.do".equals(file)) {
file = editResult();
} else if ("getHistory.do".equals(file)) {
file = getHistory();
} else if ("admin.do".equals(file)) {
file = admin();
} else if ("adminSave.do".equals(file)) {
file = adminSave();
} else if ("adminStartTranslate.do".equals(file)) {
file = adminStartTranslate();
} else if ("adminShutdown.do".equals(file)) {
file = adminShutdown();
} else if ("autoCompleteList.do".equals(file)) {
file = autoCompleteList();
} else if ("tools.do".equals(file)) {
file = tools();
} else {
file = "error.jsp";
}
}
trace("return " + file);
return file;
}
private String autoCompleteList() {
String query = (String) attributes.get("query");
boolean lowercase = false;
if (query.trim().length() > 0 &&
Character.isLowerCase(query.trim().charAt(0))) {
lowercase = true;
}
try {
String sql = query;
if (sql.endsWith(";")) {
sql += " ";
}
ScriptReader reader = new ScriptReader(new StringReader(sql));
reader.setSkipRemarks(true);
String lastSql = "";
while (true) {
String n = reader.readStatement();
if (n == null) {
break;
}
lastSql = n;
}
String result = "";
if (reader.isInsideRemark()) {
if (reader.isBlockRemark()) {
result = "1#(End Remark)# */\n" + result;
} else {
result = "1#(Newline)#\n" + result;
}
} else {
sql = lastSql;
while (sql.length() > 0 && sql.charAt(0) <= ' ') {
sql = sql.substring(1);
}
if (sql.trim().length() > 0 && Character.isLowerCase(sql.trim().charAt(0))) {
lowercase = true;
}
Bnf bnf = session.getBnf();
if (bnf == null) {
return "autoCompleteList.jsp";
}
HashMap<String, String> map = bnf.getNextTokenList(sql);
String space = "";
if (sql.length() > 0) {
char last = sql.charAt(sql.length() - 1);
if (!Character.isWhitespace(last) && (last != '.' &&
last >= ' ' && last != '\'' && last != '"')) {
space = " ";
}
}
ArrayList<String> list = New.arrayList(map.size());
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
String type = "" + key.charAt(0);
if (Integer.parseInt(type) > 2) {
continue;
}
key = key.substring(2);
if (Character.isLetter(key.charAt(0)) && lowercase) {
key = StringUtils.toLowerEnglish(key);
value = StringUtils.toLowerEnglish(value);
}
if (key.equals(value) && !".".equals(value)) {
value = space + value;
}
key = StringUtils.urlEncode(key);
key = StringUtils.replaceAll(key, "+", " ");
value = StringUtils.urlEncode(value);
value = StringUtils.replaceAll(value, "+", " ");
list.add(type + "#" + key + "#" + value);
}
Collections.sort(list);
if (query.endsWith("\n") || query.trim().endsWith(";")) {
list.add(0, "1#(Newline)#\n");
}
StatementBuilder buff = new StatementBuilder();
for (String s : list) {
buff.appendExceptFirst("|");
buff.append(s);
}
result = buff.toString();
}
session.put("autoCompleteList", result);
} catch (Throwable e) {
server.traceError(e);
}
return "autoCompleteList.jsp";
}
private String admin() {
session.put("port", "" + server.getPort());
session.put("allowOthers", "" + server.getAllowOthers());
session.put("ssl", String.valueOf(server.getSSL()));
session.put("sessions", server.getSessions());
return "admin.jsp";
}
private String adminSave() {
try {
Properties prop = new SortedProperties();
int port = Integer.decode((String) attributes.get("port"));
prop.setProperty("webPort", String.valueOf(port));
server.setPort(port);
boolean allowOthers = Boolean.parseBoolean(
(String) attributes.get("allowOthers"));
prop.setProperty("webAllowOthers", String.valueOf(allowOthers));
server.setAllowOthers(allowOthers);
boolean ssl = Boolean.parseBoolean(
(String) attributes.get("ssl"));
prop.setProperty("webSSL", String.valueOf(ssl));
server.setSSL(ssl);
server.saveProperties(prop);
} catch (Exception e) {
trace(e.toString());
}
return admin();
}
private String tools() {
try {
String toolName = (String) attributes.get("tool");
session.put("tool", toolName);
String args = (String) attributes.get("args");
String[] argList = StringUtils.arraySplit(args, ',', false);
Tool tool = null;
if ("Backup".equals(toolName)) {
tool = new Backup();
} else if ("Restore".equals(toolName)) {
tool = new Restore();
} else if ("Recover".equals(toolName)) {
tool = new Recover();
} else if ("DeleteDbFiles".equals(toolName)) {
tool = new DeleteDbFiles();
} else if ("ChangeFileEncryption".equals(toolName)) {
tool = new ChangeFileEncryption();
} else if ("Script".equals(toolName)) {
tool = new Script();
} else if ("RunScript".equals(toolName)) {
tool = new RunScript();
} else if ("ConvertTraceFile".equals(toolName)) {
tool = new ConvertTraceFile();
} else if ("CreateCluster".equals(toolName)) {
tool = new CreateCluster();
} else {
throw DbException.throwInternalError(toolName);
}
ByteArrayOutputStream outBuff = new ByteArrayOutputStream();
PrintStream out = new PrintStream(outBuff, false, "UTF-8");
tool.setOut(out);
try {
tool.runTool(argList);
out.flush();
String o = new String(outBuff.toByteArray(), Constants.UTF8);
String result = PageParser.escapeHtml(o);
session.put("toolResult", result);
} catch (Exception e) {
session.put("toolResult", getStackTrace(0, e, true));
}
} catch (Exception e) {
server.traceError(e);
}
return "tools.jsp";
}
private String adminStartTranslate() {
Map<?, ?> p = Map.class.cast(session.map.get("text"));
@SuppressWarnings("unchecked")
Map<Object, Object> p2 = (Map<Object, Object>) p;
String file = server.startTranslate(p2);
session.put("translationFile", file);
return "helpTranslate.jsp";
}
/**
* Stop the application and the server.
*
* @return the page to display
*/
protected String adminShutdown() {
server.shutdown();
return "admin.jsp";
}
private String index() {
String[][] languageArray = WebServer.LANGUAGES;
String language = (String) attributes.get("language");
Locale locale = session.locale;
if (language != null) {
if (locale == null || !StringUtils.toLowerEnglish(
locale.getLanguage()).equals(language)) {
locale = new Locale(language, "");
server.readTranslations(session, locale.getLanguage());
session.put("language", language);
session.locale = locale;
}
} else {
language = (String) session.get("language");
}
if (language == null) {
// if the language is not yet known
// use the last header
language = headerLanguage;
}
session.put("languageCombo", getComboBox(languageArray, language));
String[] settingNames = server.getSettingNames();
String setting = attributes.getProperty("setting");
if (setting == null && settingNames.length > 0) {
setting = settingNames[0];
}
String combobox = getComboBox(settingNames, setting);
session.put("settingsList", combobox);
ConnectionInfo info = server.getSetting(setting);
if (info == null) {
info = new ConnectionInfo();
}
session.put("setting", PageParser.escapeHtmlData(setting));
session.put("name", PageParser.escapeHtmlData(setting));
session.put("driver", PageParser.escapeHtmlData(info.driver));
session.put("url", PageParser.escapeHtmlData(info.url));
session.put("user", PageParser.escapeHtmlData(info.user));
return "index.jsp";
}
private String getHistory() {
int id = Integer.parseInt(attributes.getProperty("id"));
String sql = session.getCommand(id);
session.put("query", PageParser.escapeHtmlData(sql));
return "query.jsp";
}
private static int addColumns(boolean mainSchema, DbTableOrView table,
StringBuilder buff, int treeIndex, boolean showColumnTypes,
StringBuilder columnsBuffer) {
DbColumn[] columns = table.getColumns();
for (int i = 0; columns != null && i < columns.length; i++) {
DbColumn column = columns[i];
if (columnsBuffer.length() > 0) {
columnsBuffer.append(' ');
}
columnsBuffer.append(column.getName());
String col = escapeIdentifier(column.getName());
String level = mainSchema ? ", 1, 1" : ", 2, 2";
buff.append("setNode(" + treeIndex + level + ", 'column', '" +
PageParser.escapeJavaScript(column.getName()) +
"', 'javascript:ins(\\'" + col + "\\')');\n");
treeIndex++;
if (mainSchema && showColumnTypes) {
buff.append("setNode(" + treeIndex + ", 2, 2, 'type', '" +
PageParser.escapeJavaScript(column.getDataType()) +
"', null);\n");
treeIndex++;
}
}
return treeIndex;
}
private static String escapeIdentifier(String name) {
return StringUtils.urlEncode(
PageParser.escapeJavaScript(name)).replace('+', ' ');
}
/**
* This class represents index information for the GUI.
*/
static class IndexInfo {
/**
* The index name.
*/
String name;
/**
* The index type name.
*/
String type;
/**
* The indexed columns.
*/
String columns;
}
private static int addIndexes(boolean mainSchema, DatabaseMetaData meta,
String table, String schema, StringBuilder buff, int treeIndex)
throws SQLException {
ResultSet rs;
try {
rs = meta.getIndexInfo(null, schema, table, false, true);
} catch (SQLException e) {
// SQLite
return treeIndex;
}
HashMap<String, IndexInfo> indexMap = New.hashMap();
while (rs.next()) {
String name = rs.getString("INDEX_NAME");
IndexInfo info = indexMap.get(name);
if (info == null) {
int t = rs.getInt("TYPE");
String type;
if (t == DatabaseMetaData.tableIndexClustered) {
type = "";
} else if (t == DatabaseMetaData.tableIndexHashed) {
type = " (${text.tree.hashed})";
} else if (t == DatabaseMetaData.tableIndexOther) {
type = "";
} else {
type = null;
}
if (name != null && type != null) {
info = new IndexInfo();
info.name = name;
type = (rs.getBoolean("NON_UNIQUE") ?
"${text.tree.nonUnique}" : "${text.tree.unique}") + type;
info.type = type;
info.columns = rs.getString("COLUMN_NAME");
indexMap.put(name, info);
}
} else {
info.columns += ", " + rs.getString("COLUMN_NAME");
}
}
rs.close();
if (indexMap.size() > 0) {
String level = mainSchema ? ", 1, 1" : ", 2, 1";
String levelIndex = mainSchema ? ", 2, 1" : ", 3, 1";
String levelColumnType = mainSchema ? ", 3, 2" : ", 4, 2";
buff.append("setNode(" + treeIndex + level +
", 'index_az', '${text.tree.indexes}', null);\n");
treeIndex++;
for (IndexInfo info : indexMap.values()) {
buff.append("setNode(" + treeIndex + levelIndex +
", 'index', '" +
PageParser.escapeJavaScript(info.name) + "', null);\n");
treeIndex++;
buff.append("setNode(" + treeIndex + levelColumnType +
", 'type', '" + info.type + "', null);\n");
treeIndex++;
buff.append("setNode(" + treeIndex + levelColumnType +
", 'type', '" +
PageParser.escapeJavaScript(info.columns) +
"', null);\n");
treeIndex++;
}
}
return treeIndex;
}
private int addTablesAndViews(DbSchema schema, boolean mainSchema,
StringBuilder buff, int treeIndex) throws SQLException {
if (schema == null) {
return treeIndex;
}
Connection conn = session.getConnection();
DatabaseMetaData meta = session.getMetaData();
int level = mainSchema ? 0 : 1;
boolean showColumns = mainSchema || !schema.isSystem;
String indentation = ", " + level + ", " + (showColumns ? "1" : "2") + ", ";
String indentNode = ", " + (level + 1) + ", 2, ";
DbTableOrView[] tables = schema.getTables();
if (tables == null) {
return treeIndex;
}
boolean isOracle = schema.getContents().isOracle();
boolean notManyTables = tables.length < SysProperties.CONSOLE_MAX_TABLES_LIST_INDEXES;
for (DbTableOrView table : tables) {
if (table.isView()) {
continue;
}
int tableId = treeIndex;
String tab = table.getQuotedName();
if (!mainSchema) {
tab = schema.quotedName + "." + tab;
}
tab = escapeIdentifier(tab);
buff.append("setNode(" + treeIndex + indentation + " 'table', '" +
PageParser.escapeJavaScript(table.getName()) +
"', 'javascript:ins(\\'" + tab + "\\',true)');\n");
treeIndex++;
if (mainSchema || showColumns) {
StringBuilder columnsBuffer = new StringBuilder();
treeIndex = addColumns(mainSchema, table, buff, treeIndex,
notManyTables, columnsBuffer);
if (!isOracle && notManyTables) {
treeIndex = addIndexes(mainSchema, meta, table.getName(),
schema.name, buff, treeIndex);
}
buff.append("addTable('" +
PageParser.escapeJavaScript(table.getName()) + "', '" +
PageParser.escapeJavaScript(columnsBuffer.toString()) +
"', " + tableId + ");\n");
}
}
tables = schema.getTables();
for (DbTableOrView view : tables) {
if (!view.isView()) {
continue;
}
int tableId = treeIndex;
String tab = view.getQuotedName();
if (!mainSchema) {
tab = view.getSchema().quotedName + "." + tab;
}
tab = escapeIdentifier(tab);
buff.append("setNode(" + treeIndex + indentation + " 'view', '" +
PageParser.escapeJavaScript(view.getName()) +
"', 'javascript:ins(\\'" + tab + "\\',true)');\n");
treeIndex++;
if (mainSchema) {
StringBuilder columnsBuffer = new StringBuilder();
treeIndex = addColumns(mainSchema, view, buff,
treeIndex, notManyTables, columnsBuffer);
if (schema.getContents().isH2()) {
try (PreparedStatement prep = conn.prepareStatement("SELECT * FROM " +
"INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?")) {
prep.setString(1, view.getName());
ResultSet rs = prep.executeQuery();
if (rs.next()) {
String sql = rs.getString("SQL");
buff.append("setNode(" + treeIndex + indentNode +
" 'type', '" +
PageParser.escapeJavaScript(sql) +
"', null);\n");
treeIndex++;
}
rs.close();
}
}
buff.append("addTable('" +
PageParser.escapeJavaScript(view.getName()) + "', '" +
PageParser.escapeJavaScript(columnsBuffer.toString()) +
"', " + tableId + ");\n");
}
}
return treeIndex;
}
private String tables() {
DbContents contents = session.getContents();
boolean isH2 = false;
try {
String url = (String) session.get("url");
Connection conn = session.getConnection();
contents.readContents(url, conn);
session.loadBnf();
isH2 = contents.isH2();
StringBuilder buff = new StringBuilder();
buff.append("setNode(0, 0, 0, 'database', '" + PageParser.escapeJavaScript(url)
+ "', null);\n");
int treeIndex = 1;
DbSchema defaultSchema = contents.getDefaultSchema();
treeIndex = addTablesAndViews(defaultSchema, true, buff, treeIndex);
DbSchema[] schemas = contents.getSchemas();
for (DbSchema schema : schemas) {
if (schema == defaultSchema || schema == null) {
continue;
}
buff.append("setNode(" + treeIndex + ", 0, 1, 'folder', '" +
PageParser.escapeJavaScript(schema.name) +
"', null);\n");
treeIndex++;
treeIndex = addTablesAndViews(schema, false, buff, treeIndex);
}
if (isH2) {
try (Statement stat = conn.createStatement()) {
ResultSet rs = stat.executeQuery("SELECT * FROM " +
"INFORMATION_SCHEMA.SEQUENCES ORDER BY SEQUENCE_NAME");
for (int i = 0; rs.next(); i++) {
if (i == 0) {
buff.append("setNode(" + treeIndex +
", 0, 1, 'sequences', '${text.tree.sequences}', null);\n");
treeIndex++;
}
String name = rs.getString("SEQUENCE_NAME");
String current = rs.getString("CURRENT_VALUE");
String increment = rs.getString("INCREMENT");
buff.append("setNode(" + treeIndex +
", 1, 1, 'sequence', '" +
PageParser.escapeJavaScript(name) +
"', null);\n");
treeIndex++;
buff.append("setNode(" + treeIndex +
", 2, 2, 'type', '${text.tree.current}: " +
PageParser.escapeJavaScript(current) +
"', null);\n");
treeIndex++;
if (!"1".equals(increment)) {
buff.append("setNode(" +
treeIndex +
", 2, 2, 'type', '${text.tree.increment}: " +
PageParser.escapeJavaScript(increment) +
"', null);\n");
treeIndex++;
}
}
rs.close();
rs = stat.executeQuery("SELECT * FROM " +
"INFORMATION_SCHEMA.USERS ORDER BY NAME");
for (int i = 0; rs.next(); i++) {
if (i == 0) {
buff.append("setNode(" + treeIndex +
", 0, 1, 'users', '${text.tree.users}', null);\n");
treeIndex++;
}
String name = rs.getString("NAME");
String admin = rs.getString("ADMIN");
buff.append("setNode(" + treeIndex +
", 1, 1, 'user', '" +
PageParser.escapeJavaScript(name) +
"', null);\n");
treeIndex++;
if (admin.equalsIgnoreCase("TRUE")) {
buff.append("setNode(" + treeIndex +
", 2, 2, 'type', '${text.tree.admin}', null);\n");
treeIndex++;
}
}
rs.close();
}
}
DatabaseMetaData meta = session.getMetaData();
String version = meta.getDatabaseProductName() + " " +
meta.getDatabaseProductVersion();
buff.append("setNode(" + treeIndex + ", 0, 0, 'info', '" +
PageParser.escapeJavaScript(version) + "', null);\n");
buff.append("refreshQueryTables();");
session.put("tree", buff.toString());
} catch (Exception e) {
session.put("tree", "");
session.put("error", getStackTrace(0, e, isH2));
}
return "tables.jsp";
}
private String getStackTrace(int id, Throwable e, boolean isH2) {
try {
StringWriter writer = new StringWriter();
e.printStackTrace(new PrintWriter(writer));
String stackTrace = writer.toString();
stackTrace = PageParser.escapeHtml(stackTrace);
if (isH2) {
stackTrace = linkToSource(stackTrace);
}
stackTrace = StringUtils.replaceAll(stackTrace, "\t",
"&nbsp;&nbsp;&nbsp;&nbsp;");
String message = PageParser.escapeHtml(e.getMessage());
String error = "<a class=\"error\" href=\"#\" " +
"onclick=\"var x=document.getElementById('st" + id +
"').style;x.display=x.display==''?'none':'';\">" + message +
"</a>";
if (e instanceof SQLException) {
SQLException se = (SQLException) e;
error += " " + se.getSQLState() + "/" + se.getErrorCode();
if (isH2) {
int code = se.getErrorCode();
error += " <a href=\"http://h2database.com/javadoc/" +
"org/h2/api/ErrorCode.html#c" + code +
"\">(${text.a.help})</a>";
}
}
error += "<span style=\"display: none;\" id=\"st" + id +
"\"><br />" + stackTrace + "</span>";
error = formatAsError(error);
return error;
} catch (OutOfMemoryError e2) {
server.traceError(e);
return e.toString();
}
}
private static String linkToSource(String s) {
try {
StringBuilder result = new StringBuilder(s.length());
int idx = s.indexOf("<br />");
result.append(s.substring(0, idx));
while (true) {
int start = s.indexOf("org.h2.", idx);
if (start < 0) {
result.append(s.substring(idx));
break;
}
result.append(s.substring(idx, start));
int end = s.indexOf(')', start);
if (end < 0) {
result.append(s.substring(idx));
break;
}
String element = s.substring(start, end);
int open = element.lastIndexOf('(');
int dotMethod = element.lastIndexOf('.', open - 1);
int dotClass = element.lastIndexOf('.', dotMethod - 1);
String packageName = element.substring(0, dotClass);
int colon = element.lastIndexOf(':');
String file = element.substring(open + 1, colon);
String lineNumber = element.substring(colon + 1, element.length());
String fullFileName = packageName.replace('.', '/') + "/" + file;
result.append("<a href=\"http://h2database.com/html/source.html?file=");
result.append(fullFileName);
result.append("&line=");
result.append(lineNumber);
result.append("&build=");
result.append(Constants.BUILD_ID);
result.append("\">");
result.append(element);
result.append("</a>");
idx = end;
}
return result.toString();
} catch (Throwable t) {
return s;
}
}
private static String formatAsError(String s) {
return "<div class=\"error\">" + s + "</div>";
}
private String test() {
String driver = attributes.getProperty("driver", "");
String url = attributes.getProperty("url", "");
String user = attributes.getProperty("user", "");
String password = attributes.getProperty("password", "");
session.put("driver", driver);
session.put("url", url);
session.put("user", user);
boolean isH2 = url.startsWith("jdbc:h2:");
try {
long start = System.currentTimeMillis();
String profOpen = "", profClose = "";
Profiler prof = new Profiler();
prof.startCollecting();
Connection conn;
try {
conn = server.getConnection(driver, url, user, password);
} finally {
prof.stopCollecting();
profOpen = prof.getTop(3);
}
prof = new Profiler();
prof.startCollecting();
try {
JdbcUtils.closeSilently(conn);
} finally {
prof.stopCollecting();
profClose = prof.getTop(3);
}
long time = System.currentTimeMillis() - start;
String success;
if (time > 1000) {
success = "<a class=\"error\" href=\"#\" " +
"onclick=\"var x=document.getElementById('prof').style;x." +
"display=x.display==''?'none':'';\">" +
"${text.login.testSuccessful}</a>" +
"<span style=\"display: none;\" id=\"prof\"><br />" +
PageParser.escapeHtml(profOpen) +
"<br />" +
PageParser.escapeHtml(profClose) +
"</span>";
} else {
success = "${text.login.testSuccessful}";
}
session.put("error", success);
// session.put("error", "${text.login.testSuccessful}");
return "login.jsp";
} catch (Exception e) {
session.put("error", getLoginError(e, isH2));
return "login.jsp";
}
}
/**
* Get the formatted login error message.
*
* @param e the exception
* @param isH2 if the current database is a H2 database
* @return the formatted error message
*/
private String getLoginError(Exception e, boolean isH2) {
if (e instanceof JdbcSQLException &&
((JdbcSQLException) e).getErrorCode() == ErrorCode.CLASS_NOT_FOUND_1) {
return "${text.login.driverNotFound}<br />" + getStackTrace(0, e, isH2);
}
return getStackTrace(0, e, isH2);
}
private String login() {
String driver = attributes.getProperty("driver", "");
String url = attributes.getProperty("url", "");
String user = attributes.getProperty("user", "");
String password = attributes.getProperty("password", "");
session.put("autoCommit", "checked");
session.put("autoComplete", "1");
session.put("maxrows", "1000");
boolean isH2 = url.startsWith("jdbc:h2:");
try {
Connection conn = server.getConnection(driver, url, user, password);
session.setConnection(conn);
session.put("url", url);
session.put("user", user);
session.remove("error");
settingSave();
return "frame.jsp";
} catch (Exception e) {
session.put("error", getLoginError(e, isH2));
return "login.jsp";
}
}
private String logout() {
try {
Connection conn = session.getConnection();
session.setConnection(null);
session.remove("conn");
session.remove("result");
session.remove("tables");
session.remove("user");
session.remove("tool");
if (conn != null) {
if (session.getShutdownServerOnDisconnect()) {
server.shutdown();
} else {
conn.close();
}
}
} catch (Exception e) {
trace(e.toString());
}
return "index.do";
}
private String query() {
String sql = attributes.getProperty("sql").trim();
try {
ScriptReader r = new ScriptReader(new StringReader(sql));
final ArrayList<String> list = New.arrayList();
while (true) {
String s = r.readStatement();
if (s == null) {
break;
}
list.add(s);
}
final Connection conn = session.getConnection();
if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) {
String page = new String(server.getFile("result.jsp"), Constants.UTF8);
int idx = page.indexOf("${result}");
// the first element of the list is the header, the last the
// footer
list.add(0, page.substring(0, idx));
list.add(page.substring(idx + "${result}".length()));
session.put("chunks", new Iterator<String>() {
private int i;
@Override
public boolean hasNext() {
return i < list.size();
}
@Override
public String next() {
String s = list.get(i++);
if (i == 1 || i == list.size()) {
return s;
}
StringBuilder b = new StringBuilder();
query(conn, s, i - 1, list.size() - 2, b);
return b.toString();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
});
return "result.jsp";
}
String result;
StringBuilder buff = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
String s = list.get(i);
query(conn, s, i, list.size(), buff);
}
result = buff.toString();
session.put("result", result);
} catch (Throwable e) {
session.put("result", getStackTrace(0, e, session.getContents().isH2()));
}
return "result.jsp";
}
/**
* Execute a query and append the result to the buffer.
*
* @param conn the connection
* @param s the statement
* @param i the index
* @param size the number of statements
* @param buff the target buffer
*/
void query(Connection conn, String s, int i, int size, StringBuilder buff) {
if (!(s.startsWith("@") && s.endsWith("."))) {
buff.append(PageParser.escapeHtml(s + ";")).append("<br />");
}
boolean forceEdit = s.startsWith("@edit");
buff.append(getResult(conn, i + 1, s, size == 1, forceEdit)).
append("<br />");
}
private String editResult() {
ResultSet rs = session.result;
int row = Integer.parseInt(attributes.getProperty("row"));
int op = Integer.parseInt(attributes.getProperty("op"));
String result = "", error = "";
try {
if (op == 1) {
boolean insert = row < 0;
if (insert) {
rs.moveToInsertRow();
} else {
rs.absolute(row);
}
for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
String x = attributes.getProperty("r" + row + "c" + (i + 1));
unescapeData(x, rs, i + 1);
}
if (insert) {
rs.insertRow();
} else {
rs.updateRow();
}
} else if (op == 2) {
rs.absolute(row);
rs.deleteRow();
} else if (op == 3) {
// cancel
}
} catch (Throwable e) {
result = "<br />" + getStackTrace(0, e, session.getContents().isH2());
error = formatAsError(e.getMessage());
}
String sql = "@edit " + (String) session.get("resultSetSQL");
Connection conn = session.getConnection();
result = error + getResult(conn, -1, sql, true, true) + result;
session.put("result", result);
return "result.jsp";
}
private ResultSet getMetaResultSet(Connection conn, String sql)
throws SQLException {
DatabaseMetaData meta = conn.getMetaData();
if (isBuiltIn(sql, "@best_row_identifier")) {
String[] p = split(sql);
int scale = p[4] == null ? 0 : Integer.parseInt(p[4]);
boolean nullable = p[5] == null ? false : Boolean.parseBoolean(p[5]);
return meta.getBestRowIdentifier(p[1], p[2], p[3], scale, nullable);
} else if (isBuiltIn(sql, "@catalogs")) {
return meta.getCatalogs();
} else if (isBuiltIn(sql, "@columns")) {
String[] p = split(sql);
return meta.getColumns(p[1], p[2], p[3], p[4]);
} else if (isBuiltIn(sql, "@column_privileges")) {
String[] p = split(sql);
return meta.getColumnPrivileges(p[1], p[2], p[3], p[4]);
} else if (isBuiltIn(sql, "@cross_references")) {
String[] p = split(sql);
return meta.getCrossReference(p[1], p[2], p[3], p[4], p[5], p[6]);
} else if (isBuiltIn(sql, "@exported_keys")) {
String[] p = split(sql);
return meta.getExportedKeys(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@imported_keys")) {
String[] p = split(sql);
return meta.getImportedKeys(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@index_info")) {
String[] p = split(sql);
boolean unique = p[4] == null ? false : Boolean.parseBoolean(p[4]);
boolean approx = p[5] == null ? false : Boolean.parseBoolean(p[5]);
return meta.getIndexInfo(p[1], p[2], p[3], unique, approx);
} else if (isBuiltIn(sql, "@primary_keys")) {
String[] p = split(sql);
return meta.getPrimaryKeys(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@procedures")) {
String[] p = split(sql);
return meta.getProcedures(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@procedure_columns")) {
String[] p = split(sql);
return meta.getProcedureColumns(p[1], p[2], p[3], p[4]);
} else if (isBuiltIn(sql, "@schemas")) {
return meta.getSchemas();
} else if (isBuiltIn(sql, "@tables")) {
String[] p = split(sql);
String[] types = p[4] == null ? null : StringUtils.arraySplit(p[4], ',', false);
return meta.getTables(p[1], p[2], p[3], types);
} else if (isBuiltIn(sql, "@table_privileges")) {
String[] p = split(sql);
return meta.getTablePrivileges(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@table_types")) {
return meta.getTableTypes();
} else if (isBuiltIn(sql, "@type_info")) {
return meta.getTypeInfo();
} else if (isBuiltIn(sql, "@udts")) {
String[] p = split(sql);
int[] types;
if (p[4] == null) {
types = null;
} else {
String[] t = StringUtils.arraySplit(p[4], ',', false);
types = new int[t.length];
for (int i = 0; i < t.length; i++) {
types[i] = Integer.parseInt(t[i]);
}
}
return meta.getUDTs(p[1], p[2], p[3], types);
} else if (isBuiltIn(sql, "@version_columns")) {
String[] p = split(sql);
return meta.getVersionColumns(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@memory")) {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("Type", Types.VARCHAR, 0, 0);
rs.addColumn("KB", Types.VARCHAR, 0, 0);
rs.addRow("Used Memory", "" + Utils.getMemoryUsed());
rs.addRow("Free Memory", "" + Utils.getMemoryFree());
return rs;
} else if (isBuiltIn(sql, "@info")) {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("KEY", Types.VARCHAR, 0, 0);
rs.addColumn("VALUE", Types.VARCHAR, 0, 0);
rs.addRow("conn.getCatalog", conn.getCatalog());
rs.addRow("conn.getAutoCommit", "" + conn.getAutoCommit());
rs.addRow("conn.getTransactionIsolation", "" + conn.getTransactionIsolation());
rs.addRow("conn.getWarnings", "" + conn.getWarnings());
String map;
try {
map = "" + conn.getTypeMap();
} catch (SQLException e) {
map = e.toString();
}
rs.addRow("conn.getTypeMap", "" + map);
rs.addRow("conn.isReadOnly", "" + conn.isReadOnly());
rs.addRow("conn.getHoldability", "" + conn.getHoldability());
addDatabaseMetaData(rs, meta);
return rs;
} else if (isBuiltIn(sql, "@attributes")) {
String[] p = split(sql);
return meta.getAttributes(p[1], p[2], p[3], p[4]);
} else if (isBuiltIn(sql, "@super_tables")) {
String[] p = split(sql);
return meta.getSuperTables(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@super_types")) {
String[] p = split(sql);
return meta.getSuperTypes(p[1], p[2], p[3]);
} else if (isBuiltIn(sql, "@prof_stop")) {
if (profiler != null) {
profiler.stopCollecting();
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("Top Stack Trace(s)", Types.VARCHAR, 0, 0);
rs.addRow(profiler.getTop(3));
profiler = null;
return rs;
}
}
return null;
}
private static void addDatabaseMetaData(SimpleResultSet rs,
DatabaseMetaData meta) {
Method[] methods = DatabaseMetaData.class.getDeclaredMethods();
Arrays.sort(methods, new Comparator<Method>() {
@Override
public int compare(Method o1, Method o2) {
return o1.toString().compareTo(o2.toString());
}
});
for (Method m : methods) {
if (m.getParameterTypes().length == 0) {
try {
Object o = m.invoke(meta);
rs.addRow("meta." + m.getName(), "" + o);
} catch (InvocationTargetException e) {
rs.addRow("meta." + m.getName(), e.getTargetException().toString());
} catch (Exception e) {
rs.addRow("meta." + m.getName(), e.toString());
}
}
}
}
private static String[] split(String s) {
String[] list = new String[10];
String[] t = StringUtils.arraySplit(s, ' ', true);
System.arraycopy(t, 0, list, 0, t.length);
for (int i = 0; i < list.length; i++) {
if ("null".equals(list[i])) {
list[i] = null;
}
}
return list;
}
private int getMaxrows() {
String r = (String) session.get("maxrows");
int maxrows = r == null ? 0 : Integer.parseInt(r);
return maxrows;
}
private String getResult(Connection conn, int id, String sql,
boolean allowEdit, boolean forceEdit) {
try {
sql = sql.trim();
StringBuilder buff = new StringBuilder();
String sqlUpper = StringUtils.toUpperEnglish(sql);
if (sqlUpper.contains("CREATE") ||
sqlUpper.contains("DROP") ||
sqlUpper.contains("ALTER") ||
sqlUpper.contains("RUNSCRIPT")) {
String sessionId = attributes.getProperty("jsessionid");
buff.append("<script type=\"text/javascript\">" +
"parent['h2menu'].location='tables.do?jsessionid="
+ sessionId + "';</script>");
}
Statement stat;
DbContents contents = session.getContents();
if (forceEdit || (allowEdit && contents.isH2())) {
stat = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
} else {
stat = conn.createStatement();
}
ResultSet rs;
long time = System.currentTimeMillis();
boolean metadata = false;
boolean generatedKeys = false;
boolean edit = false;
boolean list = false;
if (isBuiltIn(sql, "@autocommit_true")) {
conn.setAutoCommit(true);
return "${text.result.autoCommitOn}";
} else if (isBuiltIn(sql, "@autocommit_false")) {
conn.setAutoCommit(false);
return "${text.result.autoCommitOff}";
} else if (isBuiltIn(sql, "@cancel")) {
stat = session.executingStatement;
if (stat != null) {
stat.cancel();
buff.append("${text.result.statementWasCanceled}");
} else {
buff.append("${text.result.noRunningStatement}");
}
return buff.toString();
} else if (isBuiltIn(sql, "@edit")) {
edit = true;
sql = sql.substring("@edit".length()).trim();
session.put("resultSetSQL", sql);
}
if (isBuiltIn(sql, "@list")) {
list = true;
sql = sql.substring("@list".length()).trim();
}
if (isBuiltIn(sql, "@meta")) {
metadata = true;
sql = sql.substring("@meta".length()).trim();
}
if (isBuiltIn(sql, "@generated")) {
generatedKeys = true;
sql = sql.substring("@generated".length()).trim();
} else if (isBuiltIn(sql, "@history")) {
buff.append(getCommandHistoryString());
return buff.toString();
} else if (isBuiltIn(sql, "@loop")) {
sql = sql.substring("@loop".length()).trim();
int idx = sql.indexOf(' ');
int count = Integer.decode(sql.substring(0, idx));
sql = sql.substring(idx).trim();
return executeLoop(conn, count, sql);
} else if (isBuiltIn(sql, "@maxrows")) {
int maxrows = (int) Double.parseDouble(
sql.substring("@maxrows".length()).trim());
session.put("maxrows", "" + maxrows);
return "${text.result.maxrowsSet}";
} else if (isBuiltIn(sql, "@parameter_meta")) {
sql = sql.substring("@parameter_meta".length()).trim();
PreparedStatement prep = conn.prepareStatement(sql);
buff.append(getParameterResultSet(prep.getParameterMetaData()));
return buff.toString();
} else if (isBuiltIn(sql, "@password_hash")) {
sql = sql.substring("@password_hash".length()).trim();
String[] p = split(sql);
return StringUtils.convertBytesToHex(
SHA256.getKeyPasswordHash(p[0], p[1].toCharArray()));
} else if (isBuiltIn(sql, "@prof_start")) {
if (profiler != null) {
profiler.stopCollecting();
}
profiler = new Profiler();
profiler.startCollecting();
return "Ok";
} else if (isBuiltIn(sql, "@sleep")) {
String s = sql.substring("@sleep".length()).trim();
int sleep = 1;
if (s.length() > 0) {
sleep = Integer.parseInt(s);
}
Thread.sleep(sleep * 1000);
return "Ok";
} else if (isBuiltIn(sql, "@transaction_isolation")) {
String s = sql.substring("@transaction_isolation".length()).trim();
if (s.length() > 0) {
int level = Integer.parseInt(s);
conn.setTransactionIsolation(level);
}
buff.append("Transaction Isolation: " +
conn.getTransactionIsolation() + "<br />");
buff.append(Connection.TRANSACTION_READ_UNCOMMITTED +
": read_uncommitted<br />");
buff.append(Connection.TRANSACTION_READ_COMMITTED +
": read_committed<br />");
buff.append(Connection.TRANSACTION_REPEATABLE_READ +
": repeatable_read<br />");
buff.append(Connection.TRANSACTION_SERIALIZABLE +
": serializable");
}
if (sql.startsWith("@")) {
rs = getMetaResultSet(conn, sql);
if (rs == null) {
buff.append("?: " + sql);
return buff.toString();
}
} else {
int maxrows = getMaxrows();
stat.setMaxRows(maxrows);
session.executingStatement = stat;
boolean isResultSet = stat.execute(sql);
session.addCommand(sql);
if (generatedKeys) {
rs = null;
rs = stat.getGeneratedKeys();
} else {
if (!isResultSet) {
buff.append("${text.result.updateCount}: " + stat.getUpdateCount());
time = System.currentTimeMillis() - time;
buff.append("<br />(").append(time).append(" ms)");
stat.close();
return buff.toString();
}
rs = stat.getResultSet();
}
}
time = System.currentTimeMillis() - time;
buff.append(getResultSet(sql, rs, metadata, list, edit, time, allowEdit));
// SQLWarning warning = stat.getWarnings();
// if (warning != null) {
// buff.append("<br />Warning:<br />").
// append(getStackTrace(id, warning));
// }
if (!edit) {
stat.close();
}
return buff.toString();
} catch (Throwable e) {
// throwable: including OutOfMemoryError and so on
return getStackTrace(id, e, session.getContents().isH2());
} finally {
session.executingStatement = null;
}
}
private static boolean isBuiltIn(String sql, String builtIn) {
return StringUtils.startsWithIgnoreCase(sql, builtIn);
}
private String executeLoop(Connection conn, int count, String sql)
throws SQLException {
ArrayList<Integer> params = New.arrayList();
int idx = 0;
while (!stop) {
idx = sql.indexOf('?', idx);
if (idx < 0) {
break;
}
if (isBuiltIn(sql.substring(idx), "?/*rnd*/")) {
params.add(1);
sql = sql.substring(0, idx) + "?" + sql.substring(idx + "/*rnd*/".length() + 1);
} else {
params.add(0);
}
idx++;
}
boolean prepared;
Random random = new Random(1);
long time = System.currentTimeMillis();
if (isBuiltIn(sql, "@statement")) {
sql = sql.substring("@statement".length()).trim();
prepared = false;
Statement stat = conn.createStatement();
for (int i = 0; !stop && i < count; i++) {
String s = sql;
for (Integer type : params) {
idx = s.indexOf('?');
if (type.intValue() == 1) {
s = s.substring(0, idx) + random.nextInt(count) + s.substring(idx + 1);
} else {
s = s.substring(0, idx) + i + s.substring(idx + 1);
}
}
if (stat.execute(s)) {
ResultSet rs = stat.getResultSet();
while (!stop && rs.next()) {
// maybe get the data as well
}
rs.close();
}
}
} else {
prepared = true;
PreparedStatement prep = conn.prepareStatement(sql);
for (int i = 0; !stop && i < count; i++) {
for (int j = 0; j < params.size(); j++) {
Integer type = params.get(j);
if (type.intValue() == 1) {
prep.setInt(j + 1, random.nextInt(count));
} else {
prep.setInt(j + 1, i);
}
}
if (session.getContents().isSQLite()) {
// SQLite currently throws an exception on prep.execute()
prep.executeUpdate();
} else {
if (prep.execute()) {
ResultSet rs = prep.getResultSet();
while (!stop && rs.next()) {
// maybe get the data as well
}
rs.close();
}
}
}
}
time = System.currentTimeMillis() - time;
StatementBuilder buff = new StatementBuilder();
buff.append(time).append(" ms: ").append(count).append(" * ");
if (prepared) {
buff.append("(Prepared) ");
} else {
buff.append("(Statement) ");
}
buff.append('(');
for (int p : params) {
buff.appendExceptFirst(", ");
buff.append(p == 0 ? "i" : "rnd");
}
return buff.append(") ").append(sql).toString();
}
private String getCommandHistoryString() {
StringBuilder buff = new StringBuilder();
ArrayList<String> history = session.getCommandHistory();
buff.append("<table cellspacing=0 cellpadding=0>" +
"<tr><th></th><th>Command</th></tr>");
for (int i = history.size() - 1; i >= 0; i--) {
String sql = history.get(i);
buff.append("<tr><td><a href=\"getHistory.do?id=").
append(i).
append("&jsessionid=${sessionId}\" target=\"h2query\" >").
append("<img width=16 height=16 src=\"ico_write.gif\" " +
"onmouseover = \"this.className ='icon_hover'\" ").
append("onmouseout = \"this.className ='icon'\" " +
"class=\"icon\" alt=\"${text.resultEdit.edit}\" ").
append("title=\"${text.resultEdit.edit}\" border=\"1\"/></a>").
append("</td><td>").
append(PageParser.escapeHtml(sql)).
append("</td></tr>");
}
buff.append("</table>");
return buff.toString();
}
private static String getParameterResultSet(ParameterMetaData meta)
throws SQLException {
StringBuilder buff = new StringBuilder();
if (meta == null) {
return "No parameter meta data";
}
buff.append("<table cellspacing=0 cellpadding=0>").
append("<tr><th>className</th><th>mode</th><th>type</th>").
append("<th>typeName</th><th>precision</th><th>scale</th></tr>");
for (int i = 0; i < meta.getParameterCount(); i++) {
buff.append("</tr><td>").
append(meta.getParameterClassName(i + 1)).
append("</td><td>").
append(meta.getParameterMode(i + 1)).
append("</td><td>").
append(meta.getParameterType(i + 1)).
append("</td><td>").
append(meta.getParameterTypeName(i + 1)).
append("</td><td>").
append(meta.getPrecision(i + 1)).
append("</td><td>").
append(meta.getScale(i + 1)).
append("</td></tr>");
}
buff.append("</table>");
return buff.toString();
}
private String getResultSet(String sql, ResultSet rs, boolean metadata,
boolean list, boolean edit, long time, boolean allowEdit)
throws SQLException {
int maxrows = getMaxrows();
time = System.currentTimeMillis() - time;
StringBuilder buff = new StringBuilder();
if (edit) {
buff.append("<form id=\"editing\" name=\"editing\" method=\"post\" " +
"action=\"editResult.do?jsessionid=${sessionId}\" " +
"id=\"mainForm\" target=\"h2result\">" +
"<input type=\"hidden\" name=\"op\" value=\"1\" />" +
"<input type=\"hidden\" name=\"row\" value=\"\" />" +
"<table cellspacing=0 cellpadding=0 id=\"editTable\">");
} else {
buff.append("<table cellspacing=0 cellpadding=0>");
}
if (metadata) {
SimpleResultSet r = new SimpleResultSet();
r.addColumn("#", Types.INTEGER, 0, 0);
r.addColumn("label", Types.VARCHAR, 0, 0);
r.addColumn("catalog", Types.VARCHAR, 0, 0);
r.addColumn("schema", Types.VARCHAR, 0, 0);
r.addColumn("table", Types.VARCHAR, 0, 0);
r.addColumn("column", Types.VARCHAR, 0, 0);
r.addColumn("type", Types.INTEGER, 0, 0);
r.addColumn("typeName", Types.VARCHAR, 0, 0);
r.addColumn("class", Types.VARCHAR, 0, 0);
r.addColumn("precision", Types.INTEGER, 0, 0);
r.addColumn("scale", Types.INTEGER, 0, 0);
r.addColumn("displaySize", Types.INTEGER, 0, 0);
r.addColumn("autoIncrement", Types.BOOLEAN, 0, 0);
r.addColumn("caseSensitive", Types.BOOLEAN, 0, 0);
r.addColumn("currency", Types.BOOLEAN, 0, 0);
r.addColumn("nullable", Types.INTEGER, 0, 0);
r.addColumn("readOnly", Types.BOOLEAN, 0, 0);
r.addColumn("searchable", Types.BOOLEAN, 0, 0);
r.addColumn("signed", Types.BOOLEAN, 0, 0);
r.addColumn("writable", Types.BOOLEAN, 0, 0);
r.addColumn("definitelyWritable", Types.BOOLEAN, 0, 0);
ResultSetMetaData m = rs.getMetaData();
for (int i = 1; i <= m.getColumnCount(); i++) {
r.addRow(i,
m.getColumnLabel(i),
m.getCatalogName(i),
m.getSchemaName(i),
m.getTableName(i),
m.getColumnName(i),
m.getColumnType(i),
m.getColumnTypeName(i),
m.getColumnClassName(i),
m.getPrecision(i),
m.getScale(i),
m.getColumnDisplaySize(i),
m.isAutoIncrement(i),
m.isCaseSensitive(i),
m.isCurrency(i),
m.isNullable(i),
m.isReadOnly(i),
m.isSearchable(i),
m.isSigned(i),
m.isWritable(i),
m.isDefinitelyWritable(i));
}
rs = r;
}
ResultSetMetaData meta = rs.getMetaData();
int columns = meta.getColumnCount();
int rows = 0;
if (list) {
buff.append("<tr><th>Column</th><th>Data</th></tr><tr>");
while (rs.next()) {
if (maxrows > 0 && rows >= maxrows) {
break;
}
rows++;
buff.append("<tr><td>Row #</td><td>").
append(rows).append("</tr>");
for (int i = 0; i < columns; i++) {
buff.append("<tr><td>").
append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))).
append("</td><td>").
append(escapeData(rs, i + 1)).
append("</td></tr>");
}
}
} else {
buff.append("<tr>");
if (edit) {
buff.append("<th>${text.resultEdit.action}</th>");
}
for (int i = 0; i < columns; i++) {
buff.append("<th>").
append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))).
append("</th>");
}
buff.append("</tr>");
while (rs.next()) {
if (maxrows > 0 && rows >= maxrows) {
break;
}
rows++;
buff.append("<tr>");
if (edit) {
buff.append("<td>").
append("<img onclick=\"javascript:editRow(").
append(rs.getRow()).
append(",'${sessionId}', '${text.resultEdit.save}', " +
"'${text.resultEdit.cancel}'").
append(")\" width=16 height=16 src=\"ico_write.gif\" " +
"onmouseover = \"this.className ='icon_hover'\" " +
"onmouseout = \"this.className ='icon'\" " +
"class=\"icon\" alt=\"${text.resultEdit.edit}\" " +
"title=\"${text.resultEdit.edit}\" border=\"1\"/>").
append("<a href=\"editResult.do?op=2&row=").
append(rs.getRow()).
append("&jsessionid=${sessionId}\" target=\"h2result\" >" +
"<img width=16 height=16 src=\"ico_remove.gif\" " +
"onmouseover = \"this.className ='icon_hover'\" " +
"onmouseout = \"this.className ='icon'\" " +
"class=\"icon\" alt=\"${text.resultEdit.delete}\" " +
"title=\"${text.resultEdit.delete}\" border=\"1\" /></a>").
append("</td>");
}
for (int i = 0; i < columns; i++) {
buff.append("<td>").
append(escapeData(rs, i + 1)).
append("</td>");
}
buff.append("</tr>");
}
}
boolean isUpdatable = false;
try {
if (!session.getContents().isDB2()) {
isUpdatable = rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE
&& rs.getType() != ResultSet.TYPE_FORWARD_ONLY;
}
} catch (NullPointerException e) {
// ignore
// workaround for a JDBC-ODBC bridge problem
}
if (edit) {
ResultSet old = session.result;
if (old != null) {
old.close();
}
session.result = rs;
} else {
rs.close();
}
if (edit) {
buff.append("<tr><td>").
append("<img onclick=\"javascript:editRow(-1, " +
"'${sessionId}', '${text.resultEdit.save}', '${text.resultEdit.cancel}'").
append(")\" width=16 height=16 src=\"ico_add.gif\" " +
"onmouseover = \"this.className ='icon_hover'\" " +
"onmouseout = \"this.className ='icon'\" " +
"class=\"icon\" alt=\"${text.resultEdit.add}\" " +
"title=\"${text.resultEdit.add}\" border=\"1\"/>").
append("</td>");
for (int i = 0; i < columns; i++) {
buff.append("<td></td>");
}
buff.append("</tr>");
}
buff.append("</table>");
if (edit) {
buff.append("</form>");
}
if (rows == 0) {
buff.append("(${text.result.noRows}");
} else if (rows == 1) {
buff.append("(${text.result.1row}");
} else {
buff.append('(').append(rows).append(" ${text.result.rows}");
}
buff.append(", ");
time = System.currentTimeMillis() - time;
buff.append(time).append(" ms)");
if (!edit && isUpdatable && allowEdit) {
buff.append("<br /><br />" +
"<form name=\"editResult\" method=\"post\" " +
"action=\"query.do?jsessionid=${sessionId}\" target=\"h2result\">" +
"<input type=\"submit\" class=\"button\" " +
"value=\"${text.resultEdit.editResult}\" />" +
"<input type=\"hidden\" name=\"sql\" value=\"@edit ").
append(PageParser.escapeHtmlData(sql)).
append("\" /></form>");
}
return buff.toString();
}
/**
* Save the current connection settings to the properties file.
*
* @return the file to open afterwards
*/
private String settingSave() {
ConnectionInfo info = new ConnectionInfo();
info.name = attributes.getProperty("name", "");
info.driver = attributes.getProperty("driver", "");
info.url = attributes.getProperty("url", "");
info.user = attributes.getProperty("user", "");
server.updateSetting(info);
attributes.put("setting", info.name);
server.saveProperties(null);
return "index.do";
}
private static String escapeData(ResultSet rs, int columnIndex)
throws SQLException {
String d = rs.getString(columnIndex);
if (d == null) {
return "<i>null</i>";
} else if (d.length() > 100000) {
String s;
if (isBinary(rs.getMetaData().getColumnType(columnIndex))) {
s = PageParser.escapeHtml(d.substring(0, 6)) +
"... (" + (d.length() / 2) + " ${text.result.bytes})";
} else {
s = PageParser.escapeHtml(d.substring(0, 100)) +
"... (" + d.length() + " ${text.result.characters})";
}
return "<div style='display: none'>=+</div>" + s;
} else if (d.equals("null") || d.startsWith("= ") || d.startsWith("=+")) {
return "<div style='display: none'>= </div>" + PageParser.escapeHtml(d);
} else if (d.equals("")) {
// PageParser.escapeHtml replaces "" with a non-breaking space
return "";
}
return PageParser.escapeHtml(d);
}
private static boolean isBinary(int sqlType) {
switch (sqlType) {
case Types.BINARY:
case Types.BLOB:
case Types.JAVA_OBJECT:
case Types.LONGVARBINARY:
case Types.OTHER:
case Types.VARBINARY:
return true;
}
return false;
}
private void unescapeData(String x, ResultSet rs, int columnIndex)
throws SQLException {
if (x.equals("null")) {
rs.updateNull(columnIndex);
return;
} else if (x.startsWith("=+")) {
// don't update
return;
} else if (x.equals("=*")) {
// set an appropriate default value
int type = rs.getMetaData().getColumnType(columnIndex);
switch (type) {
case Types.TIME:
rs.updateString(columnIndex, "12:00:00");
break;
case Types.TIMESTAMP:
case Types.DATE:
rs.updateString(columnIndex, "2001-01-01");
break;
default:
rs.updateString(columnIndex, "1");
break;
}
return;
} else if (x.startsWith("= ")) {
x = x.substring(2);
}
ResultSetMetaData meta = rs.getMetaData();
int type = meta.getColumnType(columnIndex);
if (session.getContents().isH2()) {
rs.updateString(columnIndex, x);
return;
}
switch (type) {
case Types.BIGINT:
rs.updateLong(columnIndex, Long.decode(x));
break;
case Types.DECIMAL:
rs.updateBigDecimal(columnIndex, new BigDecimal(x));
break;
case Types.DOUBLE:
case Types.FLOAT:
rs.updateDouble(columnIndex, Double.parseDouble(x));
break;
case Types.REAL:
rs.updateFloat(columnIndex, Float.parseFloat(x));
break;
case Types.INTEGER:
rs.updateInt(columnIndex, Integer.decode(x));
break;
case Types.TINYINT:
rs.updateShort(columnIndex, Short.decode(x));
break;
default:
rs.updateString(columnIndex, x);
}
}
private String settingRemove() {
String setting = attributes.getProperty("name", "");
server.removeSetting(setting);
ArrayList<ConnectionInfo> settings = server.getSettings();
if (settings.size() > 0) {
attributes.put("setting", settings.get(0));
}
server.saveProperties(null);
return "index.do";
}
/**
* Get the current mime type.
*
* @return the mime type
*/
String getMimeType() {
return mimeType;
}
boolean getCache() {
return cache;
}
WebSession getSession() {
return session;
}
private void trace(String s) {
server.trace(s);
}
}
\ No newline at end of file
package org.legrog.util;
// Code copied from org.h2.server.web.WebServer
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
//package org.h2.server.web;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.Connection;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.server.Service;
import org.h2.server.ShutdownHandler;
import org.h2.store.fs.FileUtils;
import org.h2.util.JdbcUtils;
import org.h2.util.MathUtils;
import org.h2.util.NetUtils;
import org.h2.util.New;
import org.h2.util.SortedProperties;
import org.h2.util.StringUtils;
import org.h2.util.Tool;
import org.h2.util.Utils;
/**
* The web server is a simple standalone HTTP server that implements the H2
* Console application. It is not optimized for performance.
*/
public class WebServer implements Service {
static final String[][] LANGUAGES = {
{ "cs", "\u010ce\u0161tina" },
{ "de", "Deutsch" },
{ "en", "English" },
{ "es", "Espa\u00f1ol" },
{ "fr", "Fran\u00e7ais" },
{ "hu", "Magyar"},
{ "ko", "\ud55c\uad6d\uc5b4"},
{ "in", "Indonesia"},
{ "it", "Italiano"},
{ "ja", "\u65e5\u672c\u8a9e"},
{ "nl", "Nederlands"},
{ "pl", "Polski"},
{ "pt_BR", "Portugu\u00eas (Brasil)"},
{ "pt_PT", "Portugu\u00eas (Europeu)"},
{ "ru", "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"},
{ "sk", "Slovensky"},
{ "tr", "T\u00fcrk\u00e7e"},
{ "uk", "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
{ "zh_CN", "\u4e2d\u6587 (\u7b80\u4f53)"},
{ "zh_TW", "\u4e2d\u6587 (\u7e41\u9ad4)"},
};
private static final String COMMAND_HISTORY = "commandHistory";
private static final String DEFAULT_LANGUAGE = "en";
private static final String[] GENERIC = {
"Generic JNDI Data Source|javax.naming.InitialContext|" +
"java:comp/env/jdbc/Test|sa",
"Generic Firebird Server|org.firebirdsql.jdbc.FBDriver|" +
"jdbc:firebirdsql:localhost:c:/temp/firebird/test|sysdba",
"Generic SQLite|org.sqlite.JDBC|" +
"jdbc:sqlite:test|sa",
"Generic DB2|com.ibm.db2.jcc.DB2Driver|" +
"jdbc:db2://localhost/test|" ,
"Generic Oracle|oracle.jdbc.driver.OracleDriver|" +
"jdbc:oracle:thin:@localhost:1521:XE|sa" ,
"Generic MS SQL Server 2000|com.microsoft.jdbc.sqlserver.SQLServerDriver|" +
"jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sqlexpress|sa",
"Generic MS SQL Server 2005|com.microsoft.sqlserver.jdbc.SQLServerDriver|" +
"jdbc:sqlserver://localhost;DatabaseName=test|sa",
"Generic PostgreSQL|org.postgresql.Driver|" +
"jdbc:postgresql:test|" ,
"Generic MySQL|com.mysql.jdbc.Driver|" +
"jdbc:mysql://localhost:3306/test|" ,
"Generic HSQLDB|org.hsqldb.jdbcDriver|" +
"jdbc:hsqldb:test;hsqldb.default_table_type=cached|sa" ,
"Generic Derby (Server)|org.apache.derby.jdbc.ClientDriver|" +
"jdbc:derby://localhost:1527/test;create=true|sa",
"Generic Derby (Embedded)|org.apache.derby.jdbc.EmbeddedDriver|" +
"jdbc:derby:test;create=true|sa",
"Generic H2 (Server)|org.h2.Driver|" +
"jdbc:h2:tcp://localhost/~/test|sa",
// this will be listed on top for new installations
"Generic H2 (Embedded)|org.h2.Driver|" +
"jdbc:h2:~/test|sa",
};
private static int ticker;
/**
* The session timeout (the default is 30 minutes).
*/
private static final long SESSION_TIMEOUT = SysProperties.CONSOLE_TIMEOUT;
// public static void main(String... args) throws IOException {
// String s = IOUtils.readStringAndClose(new java.io.FileReader(
// // "src/main/org/h2/server/web/res/_text_cs.prop"), -1);
// "src/main/org/h2/res/_messages_cs.prop"), -1);
// System.out.println(StringUtils.javaEncode("..."));
// String[] list = Locale.getISOLanguages();
// for (int i = 0; i < list.length; i++) {
// System.out.print(list[i] + " ");
// }
// System.out.println();
// String l = "de";
// String lang = new java.util.Locale(l).
// getDisplayLanguage(new java.util.Locale(l));
// System.out.println(new java.util.Locale(l).getDisplayLanguage());
// System.out.println(lang);
// java.util.Locale.CHINESE.getDisplayLanguage(java.util.Locale.CHINESE);
// for (int i = 0; i < lang.length(); i++) {
// System.out.println(Integer.toHexString(lang.charAt(i)) + " ");
// }
// }
// private URLClassLoader urlClassLoader;
private int port;
private boolean allowOthers;
private boolean isDaemon;
private final Set<WebThread> running =
Collections.synchronizedSet(new HashSet<WebThread>());
private boolean ssl;
private final HashMap<String, ConnectionInfo> connInfoMap = New.hashMap();
private long lastTimeoutCheck;
private final HashMap<String, WebSession> sessions = New.hashMap();
private final HashSet<String> languages = New.hashSet();
private String startDateTime;
private ServerSocket serverSocket;
private String url;
private ShutdownHandler shutdownHandler;
private Thread listenerThread;
private boolean ifExists;
private boolean trace;
private TranslateThread translateThread;
private boolean allowChunked = true;
private String serverPropertiesDir = Constants.SERVER_PROPERTIES_DIR;
// null means the history is not allowed to be stored
private String commandHistoryString;
/**
* Read the given file from the file system or from the resources.
*
* @param file the file name
* @return the data
*/
byte[] getFile(String file) throws IOException {
trace("getFile <" + file + ">");
byte[] data = Utils.getResource("/org/h2/server/web/res/" + file);
if (data == null) {
trace(" null");
} else {
trace(" size=" + data.length);
}
return data;
}
/**
* Check if this is a simple name (only contains '.', '-', '_', letters, or
* digits).
*
* @param s the string
* @return true if it's a simple name
*/
static boolean isSimpleName(String s) {
for (char c : s.toCharArray()) {
if (c != '.' && c != '_' && c != '-' && !Character.isLetterOrDigit(c)) {
return false;
}
}
return true;
}
/**
* Remove this web thread from the set of running threads.
*
* @param t the thread to remove
*/
synchronized void remove(WebThread t) {
running.remove(t);
}
private static String generateSessionId() {
byte[] buff = MathUtils.secureRandomBytes(16);
return StringUtils.convertBytesToHex(buff);
}
/**
* Get the web session object for the given session id.
*
* @param sessionId the session id
* @return the web session or null
*/
WebSession getSession(String sessionId) {
long now = System.currentTimeMillis();
if (lastTimeoutCheck + SESSION_TIMEOUT < now) {
for (String id : New.arrayList(sessions.keySet())) {
WebSession session = sessions.get(id);
if (session.lastAccess + SESSION_TIMEOUT < now) {
trace("timeout for " + id);
sessions.remove(id);
}
}
lastTimeoutCheck = now;
}
WebSession session = sessions.get(sessionId);
if (session != null) {
session.lastAccess = System.currentTimeMillis();
}
return session;
}
/**
* Create a new web session id and object.
*
* @param hostAddr the host address
* @return the web session object
*/
WebSession createNewSession(String hostAddr) {
String newId;
do {
newId = generateSessionId();
} while (sessions.get(newId) != null);
WebSession session = new WebSession(this);
session.lastAccess = System.currentTimeMillis();
session.put("sessionId", newId);
session.put("ip", hostAddr);
session.put("language", DEFAULT_LANGUAGE);
session.put("frame-border", "0");
session.put("frameset-border", "4");
sessions.put(newId, session);
// always read the english translation,
// so that untranslated text appears at least in english
readTranslations(session, DEFAULT_LANGUAGE);
return getSession(newId);
}
String getStartDateTime() {
if (startDateTime == null) {
SimpleDateFormat format = new SimpleDateFormat(
"EEE, d MMM yyyy HH:mm:ss z", new Locale("en", ""));
format.setTimeZone(TimeZone.getTimeZone("GMT"));
startDateTime = format.format(System.currentTimeMillis());
}
return startDateTime;
}
@Override
public void init(String... args) {
// set the serverPropertiesDir, because it's used in loadProperties()
for (int i = 0; args != null && i < args.length; i++) {
if ("-properties".equals(args[i])) {
serverPropertiesDir = args[++i];
}
}
Properties prop = loadProperties();
port = SortedProperties.getIntProperty(prop,
"webPort", Constants.DEFAULT_HTTP_PORT);
ssl = SortedProperties.getBooleanProperty(prop,
"webSSL", false);
allowOthers = SortedProperties.getBooleanProperty(prop,
"webAllowOthers", false);
commandHistoryString = prop.getProperty(COMMAND_HISTORY);
for (int i = 0; args != null && i < args.length; i++) {
String a = args[i];
if (Tool.isOption(a, "-webPort")) {
port = Integer.decode(args[++i]);
} else if (Tool.isOption(a, "-webSSL")) {
ssl = true;
} else if (Tool.isOption(a, "-webAllowOthers")) {
allowOthers = true;
} else if (Tool.isOption(a, "-webDaemon")) {
isDaemon = true;
} else if (Tool.isOption(a, "-baseDir")) {
String baseDir = args[++i];
SysProperties.setBaseDir(baseDir);
} else if (Tool.isOption(a, "-ifExists")) {
ifExists = true;
} else if (Tool.isOption(a, "-properties")) {
// already set
i++;
} else if (Tool.isOption(a, "-trace")) {
trace = true;
}
}
// if (driverList != null) {
// try {
// String[] drivers =
// StringUtils.arraySplit(driverList, ',', false);
// URL[] urls = new URL[drivers.length];
// for(int i=0; i<drivers.length; i++) {
// urls[i] = new URL(drivers[i]);
// }
// urlClassLoader = URLClassLoader.newInstance(urls);
// } catch (MalformedURLException e) {
// TraceSystem.traceThrowable(e);
// }
// }
for (String[] lang : LANGUAGES) {
languages.add(lang[0]);
}
updateURL();
}
@Override
public String getURL() {
updateURL();
return url;
}
private void updateURL() {
try {
url = (ssl ? "https" : "http") + "://" +
NetUtils.getLocalAddress() + ":" + port;
} catch (NoClassDefFoundError e) {
// Google App Engine does not allow java.net.InetAddress
}
}
@Override
public void start() {
serverSocket = NetUtils.createServerSocket(port, ssl);
port = serverSocket.getLocalPort();
updateURL();
}
@Override
public void listen() {
this.listenerThread = Thread.currentThread();
try {
while (serverSocket != null) {
Socket s = serverSocket.accept();
WebThread c = new WebThread(s, this);
running.add(c);
c.start();
}
} catch (Exception e) {
trace(e.toString());
}
}
@Override
public boolean isRunning(boolean traceError) {
if (serverSocket == null) {
return false;
}
try {
Socket s = NetUtils.createLoopbackSocket(port, ssl);
s.close();
return true;
} catch (Exception e) {
if (traceError) {
traceError(e);
}
return false;
}
}
public boolean isStopped() {
return serverSocket == null;
}
@Override
public void stop() {
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
traceError(e);
}
serverSocket = null;
}
if (listenerThread != null) {
try {
listenerThread.join(1000);
} catch (InterruptedException e) {
DbException.traceThrowable(e);
}
}
// TODO server: using a boolean 'now' argument? a timeout?
for (WebSession session : New.arrayList(sessions.values())) {
session.close();
}
for (WebThread c : New.arrayList(running)) {
try {
c.stopNow();
c.join(100);
} catch (Exception e) {
traceError(e);
}
}
}
/**
* Write trace information if trace is enabled.
*
* @param s the message to write
*/
void trace(String s) {
if (trace) {
System.out.println(s);
}
}
/**
* Write the stack trace if trace is enabled.
*
* @param e the exception
*/
void traceError(Throwable e) {
if (trace) {
e.printStackTrace();
}
}
/**
* Check if this language is supported / translated.
*
* @param language the language
* @return true if a translation is available
*/
boolean supportsLanguage(String language) {
return languages.contains(language);
}
/**
* Read the translation for this language and save them in the 'text'
* property of this session.
*
* @param session the session
* @param language the language
*/
void readTranslations(WebSession session, String language) {
Properties text = new Properties();
try {
trace("translation: "+language);
byte[] trans = getFile("_text_"+language+".prop");
trace(" "+new String(trans));
text = SortedProperties.fromLines(new String(trans, Constants.UTF8));
// remove starting # (if not translated yet)
for (Entry<Object, Object> entry : text.entrySet()) {
String value = (String) entry.getValue();
if (value.startsWith("#")) {
entry.setValue(value.substring(1));
}
}
} catch (IOException e) {
DbException.traceThrowable(e);
}
session.put("text", new HashMap<Object, Object>(text));
}
ArrayList<HashMap<String, Object>> getSessions() {
ArrayList<HashMap<String, Object>> list = New.arrayList();
for (WebSession s : sessions.values()) {
list.add(s.getInfo());
}
return list;
}
@Override
public String getType() {
return "Web Console";
}
@Override
public String getName() {
return "H2 Console Server";
}
void setAllowOthers(boolean b) {
allowOthers = b;
}
@Override
public boolean getAllowOthers() {
return allowOthers;
}
void setSSL(boolean b) {
ssl = b;
}
void setPort(int port) {
this.port = port;
}
boolean getSSL() {
return ssl;
}
@Override
public int getPort() {
return port;
}
public boolean isCommandHistoryAllowed() {
return commandHistoryString != null;
}
public void setCommandHistoryAllowed(boolean allowed) {
if (allowed) {
if (commandHistoryString == null) {
commandHistoryString = "";
}
} else {
commandHistoryString = null;
}
}
public ArrayList<String> getCommandHistoryList() {
ArrayList<String> result = New.arrayList();
if (commandHistoryString == null) {
return result;
}
// Split the commandHistoryString on non-escaped semicolons
// and unescape it.
StringBuilder sb = new StringBuilder();
for (int end = 0;; end++) {
if (end == commandHistoryString.length() ||
commandHistoryString.charAt(end) == ';') {
if (sb.length() > 0) {
result.add(sb.toString());
sb.delete(0, sb.length());
}
if (end == commandHistoryString.length()) {
break;
}
} else if (commandHistoryString.charAt(end) == '\\' &&
end < commandHistoryString.length() - 1) {
sb.append(commandHistoryString.charAt(++end));
} else {
sb.append(commandHistoryString.charAt(end));
}
}
return result;
}
/**
* Save the command history to the properties file.
*
* @param commandHistory the history
*/
public void saveCommandHistoryList(ArrayList<String> commandHistory) {
StringBuilder sb = new StringBuilder();
for (String s : commandHistory) {
if (sb.length() > 0) {
sb.append(';');
}
sb.append(s.replace("\\", "\\\\").replace(";", "\\;"));
}
commandHistoryString = sb.toString();
saveProperties(null);
}
/**
* Get the connection information for this setting.
*
* @param name the setting name
* @return the connection information
*/
ConnectionInfo getSetting(String name) {
return connInfoMap.get(name);
}
/**
* Update a connection information setting.
*
* @param info the connection information
*/
void updateSetting(ConnectionInfo info) {
connInfoMap.put(info.name, info);
info.lastAccess = ticker++;
}
/**
* Remove a connection information setting from the list
*
* @param name the setting to remove
*/
void removeSetting(String name) {
connInfoMap.remove(name);
}
private Properties loadProperties() {
try {
if ("null".equals(serverPropertiesDir)) {
return new Properties();
}
return SortedProperties.loadProperties(
serverPropertiesDir + "/" + Constants.SERVER_PROPERTIES_NAME);
} catch (Exception e) {
DbException.traceThrowable(e);
return new Properties();
}
}
/**
* Get the list of connection information setting names.
*
* @return the connection info names
*/
String[] getSettingNames() {
ArrayList<ConnectionInfo> list = getSettings();
String[] names = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
names[i] = list.get(i).name;
}
return names;
}
/**
* Get the list of connection info objects.
*
* @return the list
*/
synchronized ArrayList<ConnectionInfo> getSettings() {
ArrayList<ConnectionInfo> settings = New.arrayList();
if (connInfoMap.size() == 0) {
Properties prop = loadProperties();
if (prop.size() == 0) {
for (String gen : GENERIC) {
ConnectionInfo info = new ConnectionInfo(gen);
settings.add(info);
updateSetting(info);
}
} else {
for (int i = 0;; i++) {
String data = prop.getProperty(String.valueOf(i));
if (data == null) {
break;
}
ConnectionInfo info = new ConnectionInfo(data);
settings.add(info);
updateSetting(info);
}
}
} else {
settings.addAll(connInfoMap.values());
}
Collections.sort(settings);
return settings;
}
/**
* Save the settings to the properties file.
*
* @param prop null or the properties webPort, webAllowOthers, and webSSL
*/
synchronized void saveProperties(Properties prop) {
try {
if (prop == null) {
Properties old = loadProperties();
prop = new SortedProperties();
prop.setProperty("webPort",
"" + SortedProperties.getIntProperty(old,
"webPort", port));
prop.setProperty("webAllowOthers",
"" + SortedProperties.getBooleanProperty(old,
"webAllowOthers", allowOthers));
prop.setProperty("webSSL",
"" + SortedProperties.getBooleanProperty(old,
"webSSL", ssl));
if (commandHistoryString != null) {
prop.setProperty(COMMAND_HISTORY, commandHistoryString);
}
}
ArrayList<ConnectionInfo> settings = getSettings();
int len = settings.size();
for (int i = 0; i < len; i++) {
ConnectionInfo info = settings.get(i);
if (info != null) {
prop.setProperty(String.valueOf(len - i - 1), info.getString());
}
}
if (!"null".equals(serverPropertiesDir)) {
OutputStream out = FileUtils.newOutputStream(
serverPropertiesDir + "/" + Constants.SERVER_PROPERTIES_NAME, false);
prop.store(out, "H2 Server Properties");
out.close();
}
} catch (Exception e) {
DbException.traceThrowable(e);
}
}
/**
* Open a database connection.
*
* @param driver the driver class name
* @param databaseUrl the database URL
* @param user the user name
* @param password the password
* @return the database connection
*/
Connection getConnection(String driver, String databaseUrl, String user,
String password) throws SQLException {
driver = driver.trim();
databaseUrl = databaseUrl.trim();
org.h2.Driver.load();
Properties p = new Properties();
p.setProperty("user", user.trim());
// do not trim the password, otherwise an
// encrypted H2 database with empty user password doesn't work
p.setProperty("password", password);
if (databaseUrl.startsWith("jdbc:h2:")) {
if (ifExists) {
databaseUrl += ";IFEXISTS=TRUE";
}
// PostgreSQL would throw a NullPointerException
// if it is loaded before the H2 driver
// because it can't deal with non-String objects in the connection
// Properties
return org.h2.Driver.load().connect(databaseUrl, p);
}
// try {
// Driver dr = (Driver) urlClassLoader.
// loadClass(driver).newInstance();
// return dr.connect(url, p);
// } catch(ClassNotFoundException e2) {
// throw e2;
// }
return JdbcUtils.getConnection(driver, databaseUrl, p);
}
/**
* Shut down the web server.
*/
void shutdown() {
if (shutdownHandler != null) {
shutdownHandler.shutdown();
}
}
public void setShutdownHandler(ShutdownHandler shutdownHandler) {
this.shutdownHandler = shutdownHandler;
}
/**
* Create a session with a given connection.
*
* @param conn the connection
* @return the URL of the web site to access this connection
*/
public String addSession(Connection conn) throws SQLException {
WebSession session = createNewSession("local");
session.setShutdownServerOnDisconnect();
session.setConnection(conn);
session.put("url", conn.getMetaData().getURL());
String s = (String) session.get("sessionId");
return url + "/frame.jsp?jsessionid=" + s;
}
/**
* The translate thread reads and writes the file translation.properties
* once a second.
*/
private class TranslateThread extends Thread {
private final File file = new File("translation.properties");
private final Map<Object, Object> translation;
private volatile boolean stopNow;
TranslateThread(Map<Object, Object> translation) {
this.translation = translation;
}
public String getFileName() {
return file.getAbsolutePath();
}
public void stopNow() {
this.stopNow = true;
try {
join();
} catch (InterruptedException e) {
// ignore
}
}
@Override
public void run() {
while (!stopNow) {
try {
SortedProperties sp = new SortedProperties();
if (file.exists()) {
InputStream in = FileUtils.newInputStream(file.getName());
sp.load(in);
translation.putAll(sp);
} else {
OutputStream out = FileUtils.newOutputStream(file.getName(), false);
sp.putAll(translation);
sp.store(out, "Translation");
}
Thread.sleep(1000);
} catch (Exception e) {
traceError(e);
}
}
}
}
/**
* Start the translation thread that reads the file once a second.
*
* @param translation the translation map
* @return the name of the file to translate
*/
String startTranslate(Map<Object, Object> translation) {
if (translateThread != null) {
translateThread.stopNow();
}
translateThread = new TranslateThread(translation);
translateThread.setDaemon(true);
translateThread.start();
return translateThread.getFileName();
}
@Override
public boolean isDaemon() {
return isDaemon;
}
void setAllowChunked(boolean allowChunked) {
this.allowChunked = allowChunked;
}
boolean getAllowChunked() {
return allowChunked;
}
}
\ No newline at end of file
package org.legrog.util;
// Code copied from org.h2.server.web.WebSession
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
///package org.h2.server.web;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import org.h2.bnf.Bnf;
import org.h2.bnf.context.DbContents;
import org.h2.bnf.context.DbContextRule;
import org.h2.message.DbException;
import org.h2.util.New;
/**
* The web session keeps all data of a user session.
* This class is used by the H2 Console.
*/
class WebSession {
private static final int MAX_HISTORY = 1000;
/**
* The last time this client sent a request.
*/
long lastAccess;
/**
* The session attribute map.
*/
final HashMap<String, Object> map = New.hashMap();
/**
* The current locale.
*/
Locale locale;
/**
* The currently executing statement.
*/
Statement executingStatement;
/**
* The current updatable result set.
*/
ResultSet result;
private final WebServer server;
private final ArrayList<String> commandHistory;
private Connection conn;
private DatabaseMetaData meta;
private DbContents contents = new DbContents();
private Bnf bnf;
private boolean shutdownServerOnDisconnect;
WebSession(WebServer server) {
this.server = server;
// This must be stored in the session rather than in the server.
// Otherwise, one client could allow
// saving history for others (insecure).
this.commandHistory = server.getCommandHistoryList();
}
/**
* Put an attribute value in the map.
*
* @param key the key
* @param value the new value
*/
void put(String key, Object value) {
map.put(key, value);
}
/**
* Get the value for the given key.
*
* @param key the key
* @return the value
*/
Object get(String key) {
if ("sessions".equals(key)) {
return server.getSessions();
}
return map.get(key);
}
/**
* Remove a session attribute from the map.
*
* @param key the key
*/
void remove(String key) {
map.remove(key);
}
/**
* Get the BNF object.
*
* @return the BNF object
*/
Bnf getBnf() {
return bnf;
}
/**
* Load the SQL grammar BNF.
*/
void loadBnf() {
try {
Bnf newBnf = Bnf.getInstance(null);
DbContextRule columnRule =
new DbContextRule(contents, DbContextRule.COLUMN);
DbContextRule newAliasRule =
new DbContextRule(contents, DbContextRule.NEW_TABLE_ALIAS);
DbContextRule aliasRule =
new DbContextRule(contents, DbContextRule.TABLE_ALIAS);
DbContextRule tableRule =
new DbContextRule(contents, DbContextRule.TABLE);
DbContextRule schemaRule =
new DbContextRule(contents, DbContextRule.SCHEMA);
DbContextRule columnAliasRule =
new DbContextRule(contents, DbContextRule.COLUMN_ALIAS);
DbContextRule procedure =
new DbContextRule(contents, DbContextRule.PROCEDURE);
newBnf.updateTopic("procedure", procedure);
newBnf.updateTopic("column_name", columnRule);
newBnf.updateTopic("new_table_alias", newAliasRule);
newBnf.updateTopic("table_alias", aliasRule);
newBnf.updateTopic("column_alias", columnAliasRule);
newBnf.updateTopic("table_name", tableRule);
newBnf.updateTopic("schema_name", schemaRule);
newBnf.linkStatements();
bnf = newBnf;
} catch (Exception e) {
// ok we don't have the bnf
server.traceError(e);
}
}
/**
* Get the SQL statement from history.
*
* @param id the history id
* @return the SQL statement
*/
String getCommand(int id) {
return commandHistory.get(id);
}
/**
* Add a SQL statement to the history.
*
* @param sql the SQL statement
*/
void addCommand(String sql) {
if (sql == null) {
return;
}
sql = sql.trim();
if (sql.length() == 0) {
return;
}
if (commandHistory.size() > MAX_HISTORY) {
commandHistory.remove(0);
}
int idx = commandHistory.indexOf(sql);
if (idx >= 0) {
commandHistory.remove(idx);
}
commandHistory.add(sql);
if (server.isCommandHistoryAllowed()) {
server.saveCommandHistoryList(commandHistory);
}
}
/**
* Get the list of SQL statements in the history.
*
* @return the commands
*/
ArrayList<String> getCommandHistory() {
return commandHistory;
}
/**
* Update session meta data information and get the information in a map.
*
* @return a map containing the session meta data
*/
HashMap<String, Object> getInfo() {
HashMap<String, Object> m = New.hashMap();
m.putAll(map);
m.put("lastAccess", new Timestamp(lastAccess).toString());
try {
m.put("url", conn == null ?
"${text.admin.notConnected}" : conn.getMetaData().getURL());
m.put("user", conn == null ?
"-" : conn.getMetaData().getUserName());
m.put("lastQuery", commandHistory.size() == 0 ?
"" : commandHistory.get(0));
m.put("executing", executingStatement == null ?
"${text.admin.no}" : "${text.admin.yes}");
} catch (SQLException e) {
DbException.traceThrowable(e);
}
return m;
}
void setConnection(Connection conn) throws SQLException {
this.conn = conn;
if (conn == null) {
meta = null;
} else {
meta = conn.getMetaData();
}
contents = new DbContents();
}
DatabaseMetaData getMetaData() {
return meta;
}
Connection getConnection() {
return conn;
}
DbContents getContents() {
return contents;
}
/**
* Shutdown the server when disconnecting.
*/
void setShutdownServerOnDisconnect() {
this.shutdownServerOnDisconnect = true;
}
boolean getShutdownServerOnDisconnect() {
return shutdownServerOnDisconnect;
}
/**
* Close the connection and stop the statement if one is currently
* executing.
*/
void close() {
if (executingStatement != null) {
try {
executingStatement.cancel();
} catch (Exception e) {
// ignore
}
}
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
// ignore
}
}
}
}
\ No newline at end of file
package org.legrog.util;
// Code copied from org.h2.server.web.WebThread
/*
* Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
//package org.h2.server.web;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.Locale;
import java.util.Properties;
import java.util.StringTokenizer;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.message.DbException;
import org.h2.mvstore.DataUtils;
import org.h2.util.IOUtils;
import org.h2.util.NetUtils;
import org.h2.util.StringUtils;
//import org.h2.server.web.*;
/**
* For each connection to a session, an object of this class is created.
* This class is used by the H2 Console.
*/
class WebThread extends WebApp implements Runnable {
protected OutputStream output;
protected final Socket socket;
private final Thread thread;
private InputStream input;
private String ifModifiedSince;
WebThread(Socket socket, WebServer server) {
super(server);
this.socket = socket;
thread = new Thread(this, "H2 Console thread");
}
/**
* Start the thread.
*/
void start() {
thread.start();
}
/**
* Wait until the thread is stopped.
*
* @param millis the maximum number of milliseconds to wait
*/
void join(int millis) throws InterruptedException {
thread.join(millis);
}
/**
* Close the connection now.
*/
void stopNow() {
this.stop = true;
try {
socket.close();
} catch (IOException e) {
// ignore
}
}
private String getAllowedFile(String requestedFile) {
if (!allow()) {
return "notAllowed.jsp";
}
if (requestedFile.length() == 0) {
return "index.do";
}
return requestedFile;
}
@Override
public void run() {
try {
input = new BufferedInputStream(socket.getInputStream());
output = new BufferedOutputStream(socket.getOutputStream());
while (!stop) {
if (!process()) {
break;
}
}
} catch (Exception e) {
DbException.traceThrowable(e);
}
IOUtils.closeSilently(output);
IOUtils.closeSilently(input);
try {
socket.close();
} catch (IOException e) {
// ignore
} finally {
server.remove(this);
}
}
@SuppressWarnings("unchecked")
private boolean process() throws IOException {
boolean keepAlive = false;
String head = readHeaderLine();
if (head.startsWith("GET ") || head.startsWith("POST ")) {
int begin = head.indexOf('/'), end = head.lastIndexOf(' ');
String file;
if (begin < 0 || end < begin) {
file = "";
} else {
file = head.substring(begin + 1, end).trim();
}
trace(head + ": " + file);
file = getAllowedFile(file);
attributes = new Properties();
int paramIndex = file.indexOf("?");
session = null;
if (paramIndex >= 0) {
String attrib = file.substring(paramIndex + 1);
parseAttributes(attrib);
String sessionId = attributes.getProperty("jsessionid");
file = file.substring(0, paramIndex);
session = server.getSession(sessionId);
}
keepAlive = parseHeader();
String hostAddr = socket.getInetAddress().getHostAddress();
file = processRequest(file, hostAddr);
if (file.length() == 0) {
// asynchronous request
return true;
}
String message;
byte[] bytes;
if (cache && ifModifiedSince != null &&
ifModifiedSince.equals(server.getStartDateTime())) {
bytes = null;
message = "HTTP/1.1 304 Not Modified\r\n";
} else {
bytes = server.getFile(file);
if (bytes == null) {
message = "HTTP/1.1 404 Not Found\r\n";
bytes = ("File not found: " + file).getBytes(Constants.UTF8);
message += "Content-Length: " + bytes.length + "\r\n";
} else {
if (session != null && file.endsWith(".jsp")) {
String page = new String(bytes, Constants.UTF8);
if (SysProperties.CONSOLE_STREAM) {
Iterator<String> it = (Iterator<String>) session.map.remove("chunks");
if (it != null) {
message = "HTTP/1.1 200 OK\r\n";
message += "Content-Type: " + mimeType + "\r\n";
message += "Cache-Control: no-cache\r\n";
message += "Transfer-Encoding: chunked\r\n";
message += "\r\n";
trace(message);
output.write(message.getBytes());
while (it.hasNext()) {
String s = it.next();
s = PageParser.parse(s, session.map);
bytes = s.getBytes(Constants.UTF8);
if (bytes.length == 0) {
continue;
}
output.write(Integer.toHexString(bytes.length).getBytes());
output.write("\r\n".getBytes());
output.write(bytes);
output.write("\r\n".getBytes());
output.flush();
}
output.write("0\r\n\r\n".getBytes());
output.flush();
return keepAlive;
}
}
page = PageParser.parse(page, session.map);
bytes = page.getBytes(Constants.UTF8);
}
message = "HTTP/1.1 200 OK\r\n";
message += "Content-Type: " + mimeType + "\r\n";
if (!cache) {
message += "Cache-Control: no-cache\r\n";
} else {
message += "Cache-Control: max-age=10\r\n";
message += "Last-Modified: " + server.getStartDateTime() + "\r\n";
}
message += "Content-Length: " + bytes.length + "\r\n";
}
}
message += "\r\n";
trace(message);
output.write(message.getBytes());
if (bytes != null) {
output.write(bytes);
}
output.flush();
}
return keepAlive;
}
private String readHeaderLine() throws IOException {
StringBuilder buff = new StringBuilder();
while (true) {
int c = input.read();
if (c == -1) {
throw new IOException("Unexpected EOF");
} else if (c == '\r') {
if (input.read() == '\n') {
return buff.length() > 0 ? buff.toString() : null;
}
} else if (c == '\n') {
return buff.length() > 0 ? buff.toString() : null;
} else {
buff.append((char) c);
}
}
}
private void parseAttributes(String s) {
trace("data=" + s);
while (s != null) {
int idx = s.indexOf('=');
if (idx >= 0) {
String property = s.substring(0, idx);
s = s.substring(idx + 1);
idx = s.indexOf('&');
String value;
if (idx >= 0) {
value = s.substring(0, idx);
s = s.substring(idx + 1);
} else {
value = s;
}
String attr = StringUtils.urlDecode(value);
attributes.put(property, attr);
} else {
break;
}
}
trace(attributes.toString());
}
private boolean parseHeader() throws IOException {
boolean keepAlive = false;
trace("parseHeader");
int len = 0;
ifModifiedSince = null;
boolean multipart = false;
while (true) {
String line = readHeaderLine();
if (line == null) {
break;
}
trace(" " + line);
String lower = StringUtils.toLowerEnglish(line);
if (lower.startsWith("if-modified-since")) {
ifModifiedSince = getHeaderLineValue(line);
} else if (lower.startsWith("connection")) {
String conn = getHeaderLineValue(line);
if ("keep-alive".equals(conn)) {
keepAlive = true;
}
} else if (lower.startsWith("content-type")) {
String type = getHeaderLineValue(line);
if (type.startsWith("multipart/form-data")) {
multipart = true;
}
} else if (lower.startsWith("content-length")) {
len = Integer.parseInt(getHeaderLineValue(line));
trace("len=" + len);
} else if (lower.startsWith("user-agent")) {
boolean isWebKit = lower.contains("webkit/");
if (isWebKit && session != null) {
// workaround for what seems to be a WebKit bug:
// http://code.google.com/p/chromium/issues/detail?id=6402
session.put("frame-border", "1");
session.put("frameset-border", "2");
}
} else if (lower.startsWith("accept-language")) {
Locale locale = session == null ? null : session.locale;
if (locale == null) {
String languages = getHeaderLineValue(line);
StringTokenizer tokenizer = new StringTokenizer(languages, ",;");
while (tokenizer.hasMoreTokens()) {
String token = tokenizer.nextToken();
if (!token.startsWith("q=")) {
if (server.supportsLanguage(token)) {
int dash = token.indexOf('-');
if (dash >= 0) {
String language = token.substring(0, dash);
String country = token.substring(dash + 1);
locale = new Locale(language, country);
} else {
locale = new Locale(token, "");
}
headerLanguage = locale.getLanguage();
if (session != null) {
session.locale = locale;
session.put("language", headerLanguage);
server.readTranslations(session, headerLanguage);
}
break;
}
}
}
}
} else if (line.trim().length() == 0) {
break;
}
}
if (multipart) {
// not supported
} else if (session != null && len > 0) {
byte[] bytes = DataUtils.newBytes(len);
for (int pos = 0; pos < len;) {
pos += input.read(bytes, pos, len - pos);
}
String s = new String(bytes);
parseAttributes(s);
}
return keepAlive;
}
private static String getHeaderLineValue(String line) {
return line.substring(line.indexOf(':') + 1).trim();
}
@Override
protected String adminShutdown() {
stopNow();
return super.adminShutdown();
}
private boolean allow() {
if (server.getAllowOthers()) {
return true;
}
try {
return NetUtils.isLocalAddress(socket);
} catch (UnknownHostException e) {
server.traceError(e);
return false;
}
}
private void trace(String s) {
server.trace(s);
}
}
\ No newline at end of file