Jean-Francois Leveque

https://tree.taiga.io/project/jr-utily-grog-v3/us/195 Mettre en place une connexion h2 via servlet

1 +package org.legrog.util;
2 +// Code copied from org.h2.server.web.ConnectionInfo
3 +/*
4 + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
5 + * and the EPL 1.0 (http://h2database.com/html/license.html).
6 + * Initial Developer: H2 Group
7 + */
8 +//package org.h2.server.web;
9 +
10 + import org.h2.util.MathUtils;
11 + import org.h2.util.StringUtils;
12 +
13 +/**
14 + * The connection info object is a wrapper for database connection information
15 + * such as the database URL, user name and password.
16 + * This class is used by the H2 Console.
17 + */
18 +public class ConnectionInfo implements Comparable<ConnectionInfo> {
19 + /**
20 + * The driver class name.
21 + */
22 + public String driver;
23 +
24 + /**
25 + * The database URL.
26 + */
27 + public String url;
28 +
29 + /**
30 + * The user name.
31 + */
32 + public String user;
33 +
34 + /**
35 + * The connection display name.
36 + */
37 + String name;
38 +
39 + /**
40 + * The last time this connection was used.
41 + */
42 + int lastAccess;
43 +
44 + ConnectionInfo() {
45 + // nothing to do
46 + }
47 +
48 + public ConnectionInfo(String data) {
49 + String[] array = StringUtils.arraySplit(data, '|', false);
50 + name = get(array, 0);
51 + driver = get(array, 1);
52 + url = get(array, 2);
53 + user = get(array, 3);
54 + }
55 +
56 + private static String get(String[] array, int i) {
57 + return array != null && array.length > i ? array[i] : "";
58 + }
59 +
60 + String getString() {
61 + return StringUtils.arrayCombine(new String[] { name, driver, url, user }, '|');
62 + }
63 +
64 + @Override
65 + public int compareTo(ConnectionInfo o) {
66 + return -MathUtils.compareInt(lastAccess, o.lastAccess);
67 + }
68 +
69 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.legrog.util;
2 +
3 +import javax.servlet.annotation.WebServlet;
4 +
5 +import java.io.IOException;
6 +import java.net.InetAddress;
7 +import java.net.UnknownHostException;
8 +import java.util.ArrayList;
9 +import java.util.Enumeration;
10 +import java.util.Properties;
11 +
12 +import javax.servlet.ServletConfig;
13 +import javax.servlet.ServletOutputStream;
14 +import javax.servlet.http.HttpServlet;
15 +import javax.servlet.http.HttpServletRequest;
16 +import javax.servlet.http.HttpServletResponse;
17 +
18 +import org.h2.engine.Constants;
19 +import org.h2.server.web.PageParser;
20 +import org.h2.util.New;
21 +
22 +
23 +@WebServlet(urlPatterns="/console/*", name="H2Console", loadOnStartup=1)
24 +public class H2ConsoleServlet extends HttpServlet {
25 +// Code copied from org.h2.server.web.WebServlet
26 + private static final long serialVersionUID = 1L;
27 + private transient WebServer server;
28 +
29 + @Override
30 + public void init() {
31 + ServletConfig config = getServletConfig();
32 + Enumeration<?> en = config.getInitParameterNames();
33 + ArrayList<String> list = New.arrayList();
34 + while (en.hasMoreElements()) {
35 + String name = en.nextElement().toString();
36 + String value = config.getInitParameter(name);
37 + if (!name.startsWith("-")) {
38 + name = "-" + name;
39 + }
40 + list.add(name);
41 + if (value.length() > 0) {
42 + list.add(value);
43 + }
44 + }
45 + String[] args = new String[list.size()];
46 + list.toArray(args);
47 + server = new WebServer();
48 + server.setAllowChunked(false);
49 + server.init(args);
50 + }
51 +
52 + @Override
53 + public void destroy() {
54 + server.stop();
55 + }
56 +
57 + private boolean allow(HttpServletRequest req) {
58 + if (server.getAllowOthers()) {
59 + return true;
60 + }
61 + String addr = req.getRemoteAddr();
62 + try {
63 + InetAddress address = InetAddress.getByName(addr);
64 + return address.isLoopbackAddress();
65 + } catch (UnknownHostException e) {
66 + return false;
67 + } catch (NoClassDefFoundError e) {
68 + // Google App Engine does not allow java.net.InetAddress
69 + return false;
70 + }
71 + }
72 +
73 + private String getAllowedFile(HttpServletRequest req, String requestedFile) {
74 + if (!allow(req)) {
75 + return "notAllowed.jsp";
76 + }
77 + if (requestedFile.length() == 0) {
78 + return "index.do";
79 + }
80 + return requestedFile;
81 + }
82 +
83 + @Override
84 + public void doGet(HttpServletRequest req, HttpServletResponse resp)
85 + throws IOException {
86 + req.setCharacterEncoding("utf-8");
87 + String file = req.getPathInfo();
88 + if (file == null) {
89 + resp.sendRedirect(req.getRequestURI() + "/");
90 + return;
91 + } else if (file.startsWith("/")) {
92 + file = file.substring(1);
93 + }
94 + file = getAllowedFile(req, file);
95 +
96 + // extract the request attributes
97 + Properties attributes = new Properties();
98 + Enumeration<?> en = req.getAttributeNames();
99 + while (en.hasMoreElements()) {
100 + String name = en.nextElement().toString();
101 + String value = req.getAttribute(name).toString();
102 + attributes.put(name, value);
103 + }
104 + en = req.getParameterNames();
105 + while (en.hasMoreElements()) {
106 + String name = en.nextElement().toString();
107 + String value = req.getParameter(name);
108 + attributes.put(name, value);
109 + }
110 +
111 + WebSession session = null;
112 + String sessionId = attributes.getProperty("jsessionid");
113 + if (sessionId != null) {
114 + session = server.getSession(sessionId);
115 + }
116 + WebApp app = new WebApp(server);
117 + app.setSession(session, attributes);
118 + String ifModifiedSince = req.getHeader("if-modified-since");
119 +
120 + String hostAddr = req.getRemoteAddr();
121 + file = app.processRequest(file, hostAddr);
122 + session = app.getSession();
123 +
124 + String mimeType = app.getMimeType();
125 + boolean cache = app.getCache();
126 +
127 + if (cache && server.getStartDateTime().equals(ifModifiedSince)) {
128 + resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
129 + return;
130 + }
131 + byte[] bytes = server.getFile(file);
132 + if (bytes == null) {
133 + resp.sendError(HttpServletResponse.SC_NOT_FOUND);
134 + bytes = ("File not found: " + file).getBytes(Constants.UTF8);
135 + } else {
136 + if (session != null && file.endsWith(".jsp")) {
137 + String page = new String(bytes, Constants.UTF8);
138 + page = PageParser.parse(page, session.map);
139 + bytes = page.getBytes(Constants.UTF8);
140 + }
141 + resp.setContentType(mimeType);
142 + if (!cache) {
143 + resp.setHeader("Cache-Control", "no-cache");
144 + } else {
145 + resp.setHeader("Cache-Control", "max-age=10");
146 + resp.setHeader("Last-Modified", server.getStartDateTime());
147 + }
148 + }
149 + if (bytes != null) {
150 + ServletOutputStream out = resp.getOutputStream();
151 + out.write(bytes);
152 + }
153 + }
154 +
155 + @Override
156 + public void doPost(HttpServletRequest req, HttpServletResponse resp)
157 + throws IOException {
158 + doGet(req, resp);
159 + }
160 +}
1 +package org.legrog.util;
2 +// Code copied from org.h2.server.web.PageParser
3 +/*
4 + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
5 + * and the EPL 1.0 (http://h2database.com/html/license.html).
6 + * Initial Developer: H2 Group
7 + */
8 +//package org.h2.server.web;
9 +
10 + import java.text.ParseException;
11 + import java.util.HashMap;
12 + import java.util.List;
13 + import java.util.Map;
14 + import org.h2.util.New;
15 +
16 +/**
17 + * A page parser can parse an HTML page and replace the tags there.
18 + * This class is used by the H2 Console.
19 + */
20 +public class PageParser {
21 + private static final int TAB_WIDTH = 4;
22 +
23 + private final String page;
24 + private int pos;
25 + private final Map<String, Object> settings;
26 + private final int len;
27 + private StringBuilder result;
28 +
29 + private PageParser(String page, Map<String, Object> settings, int pos) {
30 + this.page = page;
31 + this.pos = pos;
32 + this.len = page.length();
33 + this.settings = settings;
34 + result = new StringBuilder(len);
35 + }
36 +
37 + /**
38 + * Replace the tags in the HTML page with the given settings.
39 + *
40 + * @param page the HTML page
41 + * @param settings the settings
42 + * @return the converted page
43 + */
44 + public static String parse(String page, Map<String, Object> settings) {
45 + PageParser block = new PageParser(page, settings, 0);
46 + return block.replaceTags();
47 + }
48 +
49 + private void setError(int i) {
50 + String s = page.substring(0, i) + "####BUG####" + page.substring(i);
51 + s = PageParser.escapeHtml(s);
52 + result = new StringBuilder();
53 + result.append(s);
54 + }
55 +
56 + private String parseBlockUntil(String end) throws ParseException {
57 + PageParser block = new PageParser(page, settings, pos);
58 + block.parseAll();
59 + if (!block.readIf(end)) {
60 + throw new ParseException(page, block.pos);
61 + }
62 + pos = block.pos;
63 + return block.result.toString();
64 + }
65 +
66 + private String replaceTags() {
67 + try {
68 + parseAll();
69 + if (pos != len) {
70 + setError(pos);
71 + }
72 + } catch (ParseException e) {
73 + setError(pos);
74 + }
75 + return result.toString();
76 + }
77 +
78 + @SuppressWarnings("unchecked")
79 + private void parseAll() throws ParseException {
80 + StringBuilder buff = result;
81 + String p = page;
82 + int i = pos;
83 + for (; i < len; i++) {
84 + char c = p.charAt(i);
85 + switch (c) {
86 + case '<': {
87 + if (p.charAt(i + 3) == ':' && p.charAt(i + 1) == '/') {
88 + // end tag
89 + pos = i;
90 + return;
91 + } else if (p.charAt(i + 2) == ':') {
92 + pos = i;
93 + if (readIf("<c:forEach")) {
94 + String var = readParam("var");
95 + String items = readParam("items");
96 + read(">");
97 + int start = pos;
98 + List<Object> list = (List<Object>) get(items);
99 + if (list == null) {
100 + result.append("?items?");
101 + list = New.arrayList();
102 + }
103 + if (list.size() == 0) {
104 + parseBlockUntil("</c:forEach>");
105 + }
106 + for (Object o : list) {
107 + settings.put(var, o);
108 + pos = start;
109 + String block = parseBlockUntil("</c:forEach>");
110 + result.append(block);
111 + }
112 + } else if (readIf("<c:if")) {
113 + String test = readParam("test");
114 + int eq = test.indexOf("=='");
115 + if (eq < 0) {
116 + setError(i);
117 + return;
118 + }
119 + String val = test.substring(eq + 3, test.length() - 1);
120 + test = test.substring(0, eq);
121 + String value = (String) get(test);
122 + read(">");
123 + String block = parseBlockUntil("</c:if>");
124 + pos--;
125 + if (value.equals(val)) {
126 + result.append(block);
127 + }
128 + } else {
129 + setError(i);
130 + return;
131 + }
132 + i = pos;
133 + } else {
134 + buff.append(c);
135 + }
136 + break;
137 + }
138 + case '$':
139 + if (p.length() > i + 1 && p.charAt(i + 1) == '{') {
140 + i += 2;
141 + int j = p.indexOf('}', i);
142 + if (j < 0) {
143 + setError(i);
144 + return;
145 + }
146 + String item = p.substring(i, j).trim();
147 + i = j;
148 + String s = (String) get(item);
149 + replaceTags(s);
150 + } else {
151 + buff.append(c);
152 + }
153 + break;
154 + default:
155 + buff.append(c);
156 + break;
157 + }
158 + }
159 + pos = i;
160 + }
161 +
162 + @SuppressWarnings("unchecked")
163 + private Object get(String item) {
164 + int dot = item.indexOf('.');
165 + if (dot >= 0) {
166 + String sub = item.substring(dot + 1);
167 + item = item.substring(0, dot);
168 + HashMap<String, Object> map = (HashMap<String, Object>) settings.get(item);
169 + if (map == null) {
170 + return "?" + item + "?";
171 + }
172 + return map.get(sub);
173 + }
174 + return settings.get(item);
175 + }
176 +
177 + private void replaceTags(String s) {
178 + if (s != null) {
179 + result.append(PageParser.parse(s, settings));
180 + }
181 + }
182 +
183 + private String readParam(String name) throws ParseException {
184 + read(name);
185 + read("=");
186 + read("\"");
187 + int start = pos;
188 + while (page.charAt(pos) != '"') {
189 + pos++;
190 + }
191 + int end = pos;
192 + read("\"");
193 + String s = page.substring(start, end);
194 + return PageParser.parse(s, settings);
195 + }
196 +
197 + private void skipSpaces() {
198 + while (page.charAt(pos) == ' ') {
199 + pos++;
200 + }
201 + }
202 +
203 + private void read(String s) throws ParseException {
204 + if (!readIf(s)) {
205 + throw new ParseException(s, pos);
206 + }
207 + }
208 +
209 + private boolean readIf(String s) {
210 + skipSpaces();
211 + if (page.regionMatches(pos, s, 0, s.length())) {
212 + pos += s.length();
213 + skipSpaces();
214 + return true;
215 + }
216 + return false;
217 + }
218 +
219 + /**
220 + * Convert data to HTML, but don't convert newlines and multiple spaces.
221 + *
222 + * @param s the data
223 + * @return the escaped html text
224 + */
225 + static String escapeHtmlData(String s) {
226 + return escapeHtml(s, false);
227 + }
228 +
229 + /**
230 + * Convert data to HTML, including newlines and multiple spaces.
231 + *
232 + * @param s the data
233 + * @return the escaped html text
234 + */
235 + public static String escapeHtml(String s) {
236 + return escapeHtml(s, true);
237 + }
238 +
239 + private static String escapeHtml(String s, boolean convertBreakAndSpace) {
240 + if (s == null) {
241 + return null;
242 + }
243 + if (convertBreakAndSpace) {
244 + if (s.length() == 0) {
245 + return "&nbsp;";
246 + }
247 + }
248 + StringBuilder buff = new StringBuilder(s.length());
249 + boolean convertSpace = true;
250 + for (int i = 0; i < s.length(); i++) {
251 + char c = s.charAt(i);
252 + if (c == ' ' || c == '\t') {
253 + // convert tabs into spaces
254 + for (int j = 0; j < (c == ' ' ? 1 : TAB_WIDTH); j++) {
255 + if (convertSpace && convertBreakAndSpace) {
256 + buff.append("&nbsp;");
257 + } else {
258 + buff.append(' ');
259 + convertSpace = true;
260 + }
261 + }
262 + continue;
263 + }
264 + convertSpace = false;
265 + switch (c) {
266 + case '$':
267 + // so that ${ } in the text is interpreted correctly
268 + buff.append("&#36;");
269 + break;
270 + case '<':
271 + buff.append("&lt;");
272 + break;
273 + case '>':
274 + buff.append("&gt;");
275 + break;
276 + case '&':
277 + buff.append("&amp;");
278 + break;
279 + case '"':
280 + buff.append("&quot;");
281 + break;
282 + case '\'':
283 + buff.append("&#39;");
284 + break;
285 + case '\n':
286 + if (convertBreakAndSpace) {
287 + buff.append("<br />");
288 + convertSpace = true;
289 + } else {
290 + buff.append(c);
291 + }
292 + break;
293 + default:
294 + if (c >= 128) {
295 + buff.append("&#").append((int) c).append(';');
296 + } else {
297 + buff.append(c);
298 + }
299 + break;
300 + }
301 + }
302 + return buff.toString();
303 + }
304 +
305 + /**
306 + * Escape text as a the javascript string.
307 + *
308 + * @param s the text
309 + * @return the javascript string
310 + */
311 + static String escapeJavaScript(String s) {
312 + if (s == null) {
313 + return null;
314 + }
315 + if (s.length() == 0) {
316 + return "";
317 + }
318 + StringBuilder buff = new StringBuilder(s.length());
319 + for (int i = 0; i < s.length(); i++) {
320 + char c = s.charAt(i);
321 + switch (c) {
322 + case '"':
323 + buff.append("\\\"");
324 + break;
325 + case '\'':
326 + buff.append("\\'");
327 + break;
328 + case '\\':
329 + buff.append("\\\\");
330 + break;
331 + case '\n':
332 + buff.append("\\n");
333 + break;
334 + case '\r':
335 + buff.append("\\r");
336 + break;
337 + case '\t':
338 + buff.append("\\t");
339 + break;
340 + default:
341 + buff.append(c);
342 + break;
343 + }
344 + }
345 + return buff.toString();
346 + }
347 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.legrog.util;
2 +// Code copied from org.h2.server.web.WebApp
3 +/*
4 + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
5 + * and the EPL 1.0 (http://h2database.com/html/license.html).
6 + * Initial Developer: H2 Group
7 + */
8 +//package org.h2.server.web;
9 +
10 + import java.io.ByteArrayOutputStream;
11 + import java.io.PrintStream;
12 + import java.io.PrintWriter;
13 + import java.io.StringReader;
14 + import java.io.StringWriter;
15 + import java.lang.reflect.InvocationTargetException;
16 + import java.lang.reflect.Method;
17 + import java.math.BigDecimal;
18 + import java.sql.Connection;
19 + import java.sql.DatabaseMetaData;
20 + import java.sql.ParameterMetaData;
21 + import java.sql.PreparedStatement;
22 + import java.sql.ResultSet;
23 + import java.sql.ResultSetMetaData;
24 + import java.sql.SQLException;
25 + import java.sql.Statement;
26 + import java.sql.Types;
27 + import java.util.ArrayList;
28 + import java.util.Arrays;
29 + import java.util.Collections;
30 + import java.util.Comparator;
31 + import java.util.HashMap;
32 + import java.util.Iterator;
33 + import java.util.Locale;
34 + import java.util.Map;
35 + import java.util.Properties;
36 + import java.util.Random;
37 + import org.h2.api.ErrorCode;
38 + import org.h2.bnf.Bnf;
39 + import org.h2.bnf.context.DbColumn;
40 + import org.h2.bnf.context.DbContents;
41 + import org.h2.bnf.context.DbSchema;
42 + import org.h2.bnf.context.DbTableOrView;
43 + import org.h2.engine.Constants;
44 + import org.h2.engine.SysProperties;
45 + import org.h2.jdbc.JdbcSQLException;
46 + import org.h2.message.DbException;
47 + import org.h2.security.SHA256;
48 + import org.h2.tools.Backup;
49 + import org.h2.tools.ChangeFileEncryption;
50 + import org.h2.tools.ConvertTraceFile;
51 + import org.h2.tools.CreateCluster;
52 + import org.h2.tools.DeleteDbFiles;
53 + import org.h2.tools.Recover;
54 + import org.h2.tools.Restore;
55 + import org.h2.tools.RunScript;
56 + import org.h2.tools.Script;
57 + import org.h2.tools.SimpleResultSet;
58 + import org.h2.util.JdbcUtils;
59 + import org.h2.util.New;
60 + import org.h2.util.Profiler;
61 + import org.h2.util.ScriptReader;
62 + import org.h2.util.SortedProperties;
63 + import org.h2.util.StatementBuilder;
64 + import org.h2.util.StringUtils;
65 + import org.h2.util.Tool;
66 + import org.h2.util.Utils;
67 +
68 +/**
69 + * For each connection to a session, an object of this class is created.
70 + * This class is used by the H2 Console.
71 + */
72 +public class WebApp {
73 +
74 + /**
75 + * The web server.
76 + */
77 + protected final WebServer server;
78 +
79 + /**
80 + * The session.
81 + */
82 + protected WebSession session;
83 +
84 + /**
85 + * The session attributes
86 + */
87 + protected Properties attributes;
88 +
89 + /**
90 + * The mime type of the current response.
91 + */
92 + protected String mimeType;
93 +
94 + /**
95 + * Whether the response can be cached.
96 + */
97 + protected boolean cache;
98 +
99 + /**
100 + * Whether to close the connection.
101 + */
102 + protected boolean stop;
103 +
104 + /**
105 + * The language in the HTTP header.
106 + */
107 + protected String headerLanguage;
108 +
109 + private Profiler profiler;
110 +
111 + WebApp(WebServer server) {
112 + this.server = server;
113 + }
114 +
115 + /**
116 + * Set the web session and attributes.
117 + *
118 + * @param session the session
119 + * @param attributes the attributes
120 + */
121 + void setSession(WebSession session, Properties attributes) {
122 + this.session = session;
123 + this.attributes = attributes;
124 + }
125 +
126 + /**
127 + * Process an HTTP request.
128 + *
129 + * @param file the file that was requested
130 + * @param hostAddr the host address
131 + * @return the name of the file to return to the client
132 + */
133 + String processRequest(String file, String hostAddr) {
134 + int index = file.lastIndexOf('.');
135 + String suffix;
136 + if (index >= 0) {
137 + suffix = file.substring(index + 1);
138 + } else {
139 + suffix = "";
140 + }
141 + if ("ico".equals(suffix)) {
142 + mimeType = "image/x-icon";
143 + cache = true;
144 + } else if ("gif".equals(suffix)) {
145 + mimeType = "image/gif";
146 + cache = true;
147 + } else if ("css".equals(suffix)) {
148 + cache = true;
149 + mimeType = "text/css";
150 + } else if ("html".equals(suffix) ||
151 + "do".equals(suffix) ||
152 + "jsp".equals(suffix)) {
153 + cache = false;
154 + mimeType = "text/html";
155 + if (session == null) {
156 + session = server.createNewSession(hostAddr);
157 + if (!"notAllowed.jsp".equals(file)) {
158 + file = "index.do";
159 + }
160 + }
161 + } else if ("js".equals(suffix)) {
162 + cache = true;
163 + mimeType = "text/javascript";
164 + } else {
165 + cache = true;
166 + mimeType = "application/octet-stream";
167 + }
168 + trace("mimeType=" + mimeType);
169 + trace(file);
170 + if (file.endsWith(".do")) {
171 + file = process(file);
172 + }
173 + return file;
174 + }
175 +
176 + private static String getComboBox(String[] elements, String selected) {
177 + StringBuilder buff = new StringBuilder();
178 + for (String value : elements) {
179 + buff.append("<option value=\"").
180 + append(PageParser.escapeHtmlData(value)).
181 + append('\"');
182 + if (value.equals(selected)) {
183 + buff.append(" selected");
184 + }
185 + buff.append('>').
186 + append(PageParser.escapeHtml(value)).
187 + append("</option>");
188 + }
189 + return buff.toString();
190 + }
191 +
192 + private static String getComboBox(String[][] elements, String selected) {
193 + StringBuilder buff = new StringBuilder();
194 + for (String[] n : elements) {
195 + buff.append("<option value=\"").
196 + append(PageParser.escapeHtmlData(n[0])).
197 + append('\"');
198 + if (n[0].equals(selected)) {
199 + buff.append(" selected");
200 + }
201 + buff.append('>').
202 + append(PageParser.escapeHtml(n[1])).
203 + append("</option>");
204 + }
205 + return buff.toString();
206 + }
207 +
208 + private String process(String file) {
209 + trace("process " + file);
210 + while (file.endsWith(".do")) {
211 + if ("login.do".equals(file)) {
212 + file = login();
213 + } else if ("index.do".equals(file)) {
214 + file = index();
215 + } else if ("logout.do".equals(file)) {
216 + file = logout();
217 + } else if ("settingRemove.do".equals(file)) {
218 + file = settingRemove();
219 + } else if ("settingSave.do".equals(file)) {
220 + file = settingSave();
221 + } else if ("test.do".equals(file)) {
222 + file = test();
223 + } else if ("query.do".equals(file)) {
224 + file = query();
225 + } else if ("tables.do".equals(file)) {
226 + file = tables();
227 + } else if ("editResult.do".equals(file)) {
228 + file = editResult();
229 + } else if ("getHistory.do".equals(file)) {
230 + file = getHistory();
231 + } else if ("admin.do".equals(file)) {
232 + file = admin();
233 + } else if ("adminSave.do".equals(file)) {
234 + file = adminSave();
235 + } else if ("adminStartTranslate.do".equals(file)) {
236 + file = adminStartTranslate();
237 + } else if ("adminShutdown.do".equals(file)) {
238 + file = adminShutdown();
239 + } else if ("autoCompleteList.do".equals(file)) {
240 + file = autoCompleteList();
241 + } else if ("tools.do".equals(file)) {
242 + file = tools();
243 + } else {
244 + file = "error.jsp";
245 + }
246 + }
247 + trace("return " + file);
248 + return file;
249 + }
250 +
251 + private String autoCompleteList() {
252 + String query = (String) attributes.get("query");
253 + boolean lowercase = false;
254 + if (query.trim().length() > 0 &&
255 + Character.isLowerCase(query.trim().charAt(0))) {
256 + lowercase = true;
257 + }
258 + try {
259 + String sql = query;
260 + if (sql.endsWith(";")) {
261 + sql += " ";
262 + }
263 + ScriptReader reader = new ScriptReader(new StringReader(sql));
264 + reader.setSkipRemarks(true);
265 + String lastSql = "";
266 + while (true) {
267 + String n = reader.readStatement();
268 + if (n == null) {
269 + break;
270 + }
271 + lastSql = n;
272 + }
273 + String result = "";
274 + if (reader.isInsideRemark()) {
275 + if (reader.isBlockRemark()) {
276 + result = "1#(End Remark)# */\n" + result;
277 + } else {
278 + result = "1#(Newline)#\n" + result;
279 + }
280 + } else {
281 + sql = lastSql;
282 + while (sql.length() > 0 && sql.charAt(0) <= ' ') {
283 + sql = sql.substring(1);
284 + }
285 + if (sql.trim().length() > 0 && Character.isLowerCase(sql.trim().charAt(0))) {
286 + lowercase = true;
287 + }
288 + Bnf bnf = session.getBnf();
289 + if (bnf == null) {
290 + return "autoCompleteList.jsp";
291 + }
292 + HashMap<String, String> map = bnf.getNextTokenList(sql);
293 + String space = "";
294 + if (sql.length() > 0) {
295 + char last = sql.charAt(sql.length() - 1);
296 + if (!Character.isWhitespace(last) && (last != '.' &&
297 + last >= ' ' && last != '\'' && last != '"')) {
298 + space = " ";
299 + }
300 + }
301 + ArrayList<String> list = New.arrayList(map.size());
302 + for (Map.Entry<String, String> entry : map.entrySet()) {
303 + String key = entry.getKey();
304 + String value = entry.getValue();
305 + String type = "" + key.charAt(0);
306 + if (Integer.parseInt(type) > 2) {
307 + continue;
308 + }
309 + key = key.substring(2);
310 + if (Character.isLetter(key.charAt(0)) && lowercase) {
311 + key = StringUtils.toLowerEnglish(key);
312 + value = StringUtils.toLowerEnglish(value);
313 + }
314 + if (key.equals(value) && !".".equals(value)) {
315 + value = space + value;
316 + }
317 + key = StringUtils.urlEncode(key);
318 + key = StringUtils.replaceAll(key, "+", " ");
319 + value = StringUtils.urlEncode(value);
320 + value = StringUtils.replaceAll(value, "+", " ");
321 + list.add(type + "#" + key + "#" + value);
322 + }
323 + Collections.sort(list);
324 + if (query.endsWith("\n") || query.trim().endsWith(";")) {
325 + list.add(0, "1#(Newline)#\n");
326 + }
327 + StatementBuilder buff = new StatementBuilder();
328 + for (String s : list) {
329 + buff.appendExceptFirst("|");
330 + buff.append(s);
331 + }
332 + result = buff.toString();
333 + }
334 + session.put("autoCompleteList", result);
335 + } catch (Throwable e) {
336 + server.traceError(e);
337 + }
338 + return "autoCompleteList.jsp";
339 + }
340 +
341 + private String admin() {
342 + session.put("port", "" + server.getPort());
343 + session.put("allowOthers", "" + server.getAllowOthers());
344 + session.put("ssl", String.valueOf(server.getSSL()));
345 + session.put("sessions", server.getSessions());
346 + return "admin.jsp";
347 + }
348 +
349 + private String adminSave() {
350 + try {
351 + Properties prop = new SortedProperties();
352 + int port = Integer.decode((String) attributes.get("port"));
353 + prop.setProperty("webPort", String.valueOf(port));
354 + server.setPort(port);
355 + boolean allowOthers = Boolean.parseBoolean(
356 + (String) attributes.get("allowOthers"));
357 + prop.setProperty("webAllowOthers", String.valueOf(allowOthers));
358 + server.setAllowOthers(allowOthers);
359 + boolean ssl = Boolean.parseBoolean(
360 + (String) attributes.get("ssl"));
361 + prop.setProperty("webSSL", String.valueOf(ssl));
362 + server.setSSL(ssl);
363 + server.saveProperties(prop);
364 + } catch (Exception e) {
365 + trace(e.toString());
366 + }
367 + return admin();
368 + }
369 +
370 + private String tools() {
371 + try {
372 + String toolName = (String) attributes.get("tool");
373 + session.put("tool", toolName);
374 + String args = (String) attributes.get("args");
375 + String[] argList = StringUtils.arraySplit(args, ',', false);
376 + Tool tool = null;
377 + if ("Backup".equals(toolName)) {
378 + tool = new Backup();
379 + } else if ("Restore".equals(toolName)) {
380 + tool = new Restore();
381 + } else if ("Recover".equals(toolName)) {
382 + tool = new Recover();
383 + } else if ("DeleteDbFiles".equals(toolName)) {
384 + tool = new DeleteDbFiles();
385 + } else if ("ChangeFileEncryption".equals(toolName)) {
386 + tool = new ChangeFileEncryption();
387 + } else if ("Script".equals(toolName)) {
388 + tool = new Script();
389 + } else if ("RunScript".equals(toolName)) {
390 + tool = new RunScript();
391 + } else if ("ConvertTraceFile".equals(toolName)) {
392 + tool = new ConvertTraceFile();
393 + } else if ("CreateCluster".equals(toolName)) {
394 + tool = new CreateCluster();
395 + } else {
396 + throw DbException.throwInternalError(toolName);
397 + }
398 + ByteArrayOutputStream outBuff = new ByteArrayOutputStream();
399 + PrintStream out = new PrintStream(outBuff, false, "UTF-8");
400 + tool.setOut(out);
401 + try {
402 + tool.runTool(argList);
403 + out.flush();
404 + String o = new String(outBuff.toByteArray(), Constants.UTF8);
405 + String result = PageParser.escapeHtml(o);
406 + session.put("toolResult", result);
407 + } catch (Exception e) {
408 + session.put("toolResult", getStackTrace(0, e, true));
409 + }
410 + } catch (Exception e) {
411 + server.traceError(e);
412 + }
413 + return "tools.jsp";
414 + }
415 +
416 + private String adminStartTranslate() {
417 + Map<?, ?> p = Map.class.cast(session.map.get("text"));
418 + @SuppressWarnings("unchecked")
419 + Map<Object, Object> p2 = (Map<Object, Object>) p;
420 + String file = server.startTranslate(p2);
421 + session.put("translationFile", file);
422 + return "helpTranslate.jsp";
423 + }
424 +
425 + /**
426 + * Stop the application and the server.
427 + *
428 + * @return the page to display
429 + */
430 + protected String adminShutdown() {
431 + server.shutdown();
432 + return "admin.jsp";
433 + }
434 +
435 + private String index() {
436 + String[][] languageArray = WebServer.LANGUAGES;
437 + String language = (String) attributes.get("language");
438 + Locale locale = session.locale;
439 + if (language != null) {
440 + if (locale == null || !StringUtils.toLowerEnglish(
441 + locale.getLanguage()).equals(language)) {
442 + locale = new Locale(language, "");
443 + server.readTranslations(session, locale.getLanguage());
444 + session.put("language", language);
445 + session.locale = locale;
446 + }
447 + } else {
448 + language = (String) session.get("language");
449 + }
450 + if (language == null) {
451 + // if the language is not yet known
452 + // use the last header
453 + language = headerLanguage;
454 + }
455 + session.put("languageCombo", getComboBox(languageArray, language));
456 + String[] settingNames = server.getSettingNames();
457 + String setting = attributes.getProperty("setting");
458 + if (setting == null && settingNames.length > 0) {
459 + setting = settingNames[0];
460 + }
461 + String combobox = getComboBox(settingNames, setting);
462 + session.put("settingsList", combobox);
463 + ConnectionInfo info = server.getSetting(setting);
464 + if (info == null) {
465 + info = new ConnectionInfo();
466 + }
467 + session.put("setting", PageParser.escapeHtmlData(setting));
468 + session.put("name", PageParser.escapeHtmlData(setting));
469 + session.put("driver", PageParser.escapeHtmlData(info.driver));
470 + session.put("url", PageParser.escapeHtmlData(info.url));
471 + session.put("user", PageParser.escapeHtmlData(info.user));
472 + return "index.jsp";
473 + }
474 +
475 + private String getHistory() {
476 + int id = Integer.parseInt(attributes.getProperty("id"));
477 + String sql = session.getCommand(id);
478 + session.put("query", PageParser.escapeHtmlData(sql));
479 + return "query.jsp";
480 + }
481 +
482 + private static int addColumns(boolean mainSchema, DbTableOrView table,
483 + StringBuilder buff, int treeIndex, boolean showColumnTypes,
484 + StringBuilder columnsBuffer) {
485 + DbColumn[] columns = table.getColumns();
486 + for (int i = 0; columns != null && i < columns.length; i++) {
487 + DbColumn column = columns[i];
488 + if (columnsBuffer.length() > 0) {
489 + columnsBuffer.append(' ');
490 + }
491 + columnsBuffer.append(column.getName());
492 + String col = escapeIdentifier(column.getName());
493 + String level = mainSchema ? ", 1, 1" : ", 2, 2";
494 + buff.append("setNode(" + treeIndex + level + ", 'column', '" +
495 + PageParser.escapeJavaScript(column.getName()) +
496 + "', 'javascript:ins(\\'" + col + "\\')');\n");
497 + treeIndex++;
498 + if (mainSchema && showColumnTypes) {
499 + buff.append("setNode(" + treeIndex + ", 2, 2, 'type', '" +
500 + PageParser.escapeJavaScript(column.getDataType()) +
501 + "', null);\n");
502 + treeIndex++;
503 + }
504 + }
505 + return treeIndex;
506 + }
507 +
508 + private static String escapeIdentifier(String name) {
509 + return StringUtils.urlEncode(
510 + PageParser.escapeJavaScript(name)).replace('+', ' ');
511 + }
512 +
513 + /**
514 + * This class represents index information for the GUI.
515 + */
516 + static class IndexInfo {
517 +
518 + /**
519 + * The index name.
520 + */
521 + String name;
522 +
523 + /**
524 + * The index type name.
525 + */
526 + String type;
527 +
528 + /**
529 + * The indexed columns.
530 + */
531 + String columns;
532 + }
533 +
534 + private static int addIndexes(boolean mainSchema, DatabaseMetaData meta,
535 + String table, String schema, StringBuilder buff, int treeIndex)
536 + throws SQLException {
537 + ResultSet rs;
538 + try {
539 + rs = meta.getIndexInfo(null, schema, table, false, true);
540 + } catch (SQLException e) {
541 + // SQLite
542 + return treeIndex;
543 + }
544 + HashMap<String, IndexInfo> indexMap = New.hashMap();
545 + while (rs.next()) {
546 + String name = rs.getString("INDEX_NAME");
547 + IndexInfo info = indexMap.get(name);
548 + if (info == null) {
549 + int t = rs.getInt("TYPE");
550 + String type;
551 + if (t == DatabaseMetaData.tableIndexClustered) {
552 + type = "";
553 + } else if (t == DatabaseMetaData.tableIndexHashed) {
554 + type = " (${text.tree.hashed})";
555 + } else if (t == DatabaseMetaData.tableIndexOther) {
556 + type = "";
557 + } else {
558 + type = null;
559 + }
560 + if (name != null && type != null) {
561 + info = new IndexInfo();
562 + info.name = name;
563 + type = (rs.getBoolean("NON_UNIQUE") ?
564 + "${text.tree.nonUnique}" : "${text.tree.unique}") + type;
565 + info.type = type;
566 + info.columns = rs.getString("COLUMN_NAME");
567 + indexMap.put(name, info);
568 + }
569 + } else {
570 + info.columns += ", " + rs.getString("COLUMN_NAME");
571 + }
572 + }
573 + rs.close();
574 + if (indexMap.size() > 0) {
575 + String level = mainSchema ? ", 1, 1" : ", 2, 1";
576 + String levelIndex = mainSchema ? ", 2, 1" : ", 3, 1";
577 + String levelColumnType = mainSchema ? ", 3, 2" : ", 4, 2";
578 + buff.append("setNode(" + treeIndex + level +
579 + ", 'index_az', '${text.tree.indexes}', null);\n");
580 + treeIndex++;
581 + for (IndexInfo info : indexMap.values()) {
582 + buff.append("setNode(" + treeIndex + levelIndex +
583 + ", 'index', '" +
584 + PageParser.escapeJavaScript(info.name) + "', null);\n");
585 + treeIndex++;
586 + buff.append("setNode(" + treeIndex + levelColumnType +
587 + ", 'type', '" + info.type + "', null);\n");
588 + treeIndex++;
589 + buff.append("setNode(" + treeIndex + levelColumnType +
590 + ", 'type', '" +
591 + PageParser.escapeJavaScript(info.columns) +
592 + "', null);\n");
593 + treeIndex++;
594 + }
595 + }
596 + return treeIndex;
597 + }
598 +
599 + private int addTablesAndViews(DbSchema schema, boolean mainSchema,
600 + StringBuilder buff, int treeIndex) throws SQLException {
601 + if (schema == null) {
602 + return treeIndex;
603 + }
604 + Connection conn = session.getConnection();
605 + DatabaseMetaData meta = session.getMetaData();
606 + int level = mainSchema ? 0 : 1;
607 + boolean showColumns = mainSchema || !schema.isSystem;
608 + String indentation = ", " + level + ", " + (showColumns ? "1" : "2") + ", ";
609 + String indentNode = ", " + (level + 1) + ", 2, ";
610 + DbTableOrView[] tables = schema.getTables();
611 + if (tables == null) {
612 + return treeIndex;
613 + }
614 + boolean isOracle = schema.getContents().isOracle();
615 + boolean notManyTables = tables.length < SysProperties.CONSOLE_MAX_TABLES_LIST_INDEXES;
616 + for (DbTableOrView table : tables) {
617 + if (table.isView()) {
618 + continue;
619 + }
620 + int tableId = treeIndex;
621 + String tab = table.getQuotedName();
622 + if (!mainSchema) {
623 + tab = schema.quotedName + "." + tab;
624 + }
625 + tab = escapeIdentifier(tab);
626 + buff.append("setNode(" + treeIndex + indentation + " 'table', '" +
627 + PageParser.escapeJavaScript(table.getName()) +
628 + "', 'javascript:ins(\\'" + tab + "\\',true)');\n");
629 + treeIndex++;
630 + if (mainSchema || showColumns) {
631 + StringBuilder columnsBuffer = new StringBuilder();
632 + treeIndex = addColumns(mainSchema, table, buff, treeIndex,
633 + notManyTables, columnsBuffer);
634 + if (!isOracle && notManyTables) {
635 + treeIndex = addIndexes(mainSchema, meta, table.getName(),
636 + schema.name, buff, treeIndex);
637 + }
638 + buff.append("addTable('" +
639 + PageParser.escapeJavaScript(table.getName()) + "', '" +
640 + PageParser.escapeJavaScript(columnsBuffer.toString()) +
641 + "', " + tableId + ");\n");
642 + }
643 + }
644 + tables = schema.getTables();
645 + for (DbTableOrView view : tables) {
646 + if (!view.isView()) {
647 + continue;
648 + }
649 + int tableId = treeIndex;
650 + String tab = view.getQuotedName();
651 + if (!mainSchema) {
652 + tab = view.getSchema().quotedName + "." + tab;
653 + }
654 + tab = escapeIdentifier(tab);
655 + buff.append("setNode(" + treeIndex + indentation + " 'view', '" +
656 + PageParser.escapeJavaScript(view.getName()) +
657 + "', 'javascript:ins(\\'" + tab + "\\',true)');\n");
658 + treeIndex++;
659 + if (mainSchema) {
660 + StringBuilder columnsBuffer = new StringBuilder();
661 + treeIndex = addColumns(mainSchema, view, buff,
662 + treeIndex, notManyTables, columnsBuffer);
663 + if (schema.getContents().isH2()) {
664 +
665 + try (PreparedStatement prep = conn.prepareStatement("SELECT * FROM " +
666 + "INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=?")) {
667 + prep.setString(1, view.getName());
668 + ResultSet rs = prep.executeQuery();
669 + if (rs.next()) {
670 + String sql = rs.getString("SQL");
671 + buff.append("setNode(" + treeIndex + indentNode +
672 + " 'type', '" +
673 + PageParser.escapeJavaScript(sql) +
674 + "', null);\n");
675 + treeIndex++;
676 + }
677 + rs.close();
678 + }
679 + }
680 + buff.append("addTable('" +
681 + PageParser.escapeJavaScript(view.getName()) + "', '" +
682 + PageParser.escapeJavaScript(columnsBuffer.toString()) +
683 + "', " + tableId + ");\n");
684 + }
685 + }
686 + return treeIndex;
687 + }
688 +
689 + private String tables() {
690 + DbContents contents = session.getContents();
691 + boolean isH2 = false;
692 + try {
693 + String url = (String) session.get("url");
694 + Connection conn = session.getConnection();
695 + contents.readContents(url, conn);
696 + session.loadBnf();
697 + isH2 = contents.isH2();
698 +
699 + StringBuilder buff = new StringBuilder();
700 + buff.append("setNode(0, 0, 0, 'database', '" + PageParser.escapeJavaScript(url)
701 + + "', null);\n");
702 + int treeIndex = 1;
703 +
704 + DbSchema defaultSchema = contents.getDefaultSchema();
705 + treeIndex = addTablesAndViews(defaultSchema, true, buff, treeIndex);
706 + DbSchema[] schemas = contents.getSchemas();
707 + for (DbSchema schema : schemas) {
708 + if (schema == defaultSchema || schema == null) {
709 + continue;
710 + }
711 + buff.append("setNode(" + treeIndex + ", 0, 1, 'folder', '" +
712 + PageParser.escapeJavaScript(schema.name) +
713 + "', null);\n");
714 + treeIndex++;
715 + treeIndex = addTablesAndViews(schema, false, buff, treeIndex);
716 + }
717 + if (isH2) {
718 + try (Statement stat = conn.createStatement()) {
719 + ResultSet rs = stat.executeQuery("SELECT * FROM " +
720 + "INFORMATION_SCHEMA.SEQUENCES ORDER BY SEQUENCE_NAME");
721 + for (int i = 0; rs.next(); i++) {
722 + if (i == 0) {
723 + buff.append("setNode(" + treeIndex +
724 + ", 0, 1, 'sequences', '${text.tree.sequences}', null);\n");
725 + treeIndex++;
726 + }
727 + String name = rs.getString("SEQUENCE_NAME");
728 + String current = rs.getString("CURRENT_VALUE");
729 + String increment = rs.getString("INCREMENT");
730 + buff.append("setNode(" + treeIndex +
731 + ", 1, 1, 'sequence', '" +
732 + PageParser.escapeJavaScript(name) +
733 + "', null);\n");
734 + treeIndex++;
735 + buff.append("setNode(" + treeIndex +
736 + ", 2, 2, 'type', '${text.tree.current}: " +
737 + PageParser.escapeJavaScript(current) +
738 + "', null);\n");
739 + treeIndex++;
740 + if (!"1".equals(increment)) {
741 + buff.append("setNode(" +
742 + treeIndex +
743 + ", 2, 2, 'type', '${text.tree.increment}: " +
744 + PageParser.escapeJavaScript(increment) +
745 + "', null);\n");
746 + treeIndex++;
747 + }
748 + }
749 + rs.close();
750 + rs = stat.executeQuery("SELECT * FROM " +
751 + "INFORMATION_SCHEMA.USERS ORDER BY NAME");
752 + for (int i = 0; rs.next(); i++) {
753 + if (i == 0) {
754 + buff.append("setNode(" + treeIndex +
755 + ", 0, 1, 'users', '${text.tree.users}', null);\n");
756 + treeIndex++;
757 + }
758 + String name = rs.getString("NAME");
759 + String admin = rs.getString("ADMIN");
760 + buff.append("setNode(" + treeIndex +
761 + ", 1, 1, 'user', '" +
762 + PageParser.escapeJavaScript(name) +
763 + "', null);\n");
764 + treeIndex++;
765 + if (admin.equalsIgnoreCase("TRUE")) {
766 + buff.append("setNode(" + treeIndex +
767 + ", 2, 2, 'type', '${text.tree.admin}', null);\n");
768 + treeIndex++;
769 + }
770 + }
771 + rs.close();
772 + }
773 + }
774 + DatabaseMetaData meta = session.getMetaData();
775 + String version = meta.getDatabaseProductName() + " " +
776 + meta.getDatabaseProductVersion();
777 + buff.append("setNode(" + treeIndex + ", 0, 0, 'info', '" +
778 + PageParser.escapeJavaScript(version) + "', null);\n");
779 + buff.append("refreshQueryTables();");
780 + session.put("tree", buff.toString());
781 + } catch (Exception e) {
782 + session.put("tree", "");
783 + session.put("error", getStackTrace(0, e, isH2));
784 + }
785 + return "tables.jsp";
786 + }
787 +
788 + private String getStackTrace(int id, Throwable e, boolean isH2) {
789 + try {
790 + StringWriter writer = new StringWriter();
791 + e.printStackTrace(new PrintWriter(writer));
792 + String stackTrace = writer.toString();
793 + stackTrace = PageParser.escapeHtml(stackTrace);
794 + if (isH2) {
795 + stackTrace = linkToSource(stackTrace);
796 + }
797 + stackTrace = StringUtils.replaceAll(stackTrace, "\t",
798 + "&nbsp;&nbsp;&nbsp;&nbsp;");
799 + String message = PageParser.escapeHtml(e.getMessage());
800 + String error = "<a class=\"error\" href=\"#\" " +
801 + "onclick=\"var x=document.getElementById('st" + id +
802 + "').style;x.display=x.display==''?'none':'';\">" + message +
803 + "</a>";
804 + if (e instanceof SQLException) {
805 + SQLException se = (SQLException) e;
806 + error += " " + se.getSQLState() + "/" + se.getErrorCode();
807 + if (isH2) {
808 + int code = se.getErrorCode();
809 + error += " <a href=\"http://h2database.com/javadoc/" +
810 + "org/h2/api/ErrorCode.html#c" + code +
811 + "\">(${text.a.help})</a>";
812 + }
813 + }
814 + error += "<span style=\"display: none;\" id=\"st" + id +
815 + "\"><br />" + stackTrace + "</span>";
816 + error = formatAsError(error);
817 + return error;
818 + } catch (OutOfMemoryError e2) {
819 + server.traceError(e);
820 + return e.toString();
821 + }
822 + }
823 +
824 + private static String linkToSource(String s) {
825 + try {
826 + StringBuilder result = new StringBuilder(s.length());
827 + int idx = s.indexOf("<br />");
828 + result.append(s.substring(0, idx));
829 + while (true) {
830 + int start = s.indexOf("org.h2.", idx);
831 + if (start < 0) {
832 + result.append(s.substring(idx));
833 + break;
834 + }
835 + result.append(s.substring(idx, start));
836 + int end = s.indexOf(')', start);
837 + if (end < 0) {
838 + result.append(s.substring(idx));
839 + break;
840 + }
841 + String element = s.substring(start, end);
842 + int open = element.lastIndexOf('(');
843 + int dotMethod = element.lastIndexOf('.', open - 1);
844 + int dotClass = element.lastIndexOf('.', dotMethod - 1);
845 + String packageName = element.substring(0, dotClass);
846 + int colon = element.lastIndexOf(':');
847 + String file = element.substring(open + 1, colon);
848 + String lineNumber = element.substring(colon + 1, element.length());
849 + String fullFileName = packageName.replace('.', '/') + "/" + file;
850 + result.append("<a href=\"http://h2database.com/html/source.html?file=");
851 + result.append(fullFileName);
852 + result.append("&line=");
853 + result.append(lineNumber);
854 + result.append("&build=");
855 + result.append(Constants.BUILD_ID);
856 + result.append("\">");
857 + result.append(element);
858 + result.append("</a>");
859 + idx = end;
860 + }
861 + return result.toString();
862 + } catch (Throwable t) {
863 + return s;
864 + }
865 + }
866 +
867 + private static String formatAsError(String s) {
868 + return "<div class=\"error\">" + s + "</div>";
869 + }
870 +
871 + private String test() {
872 + String driver = attributes.getProperty("driver", "");
873 + String url = attributes.getProperty("url", "");
874 + String user = attributes.getProperty("user", "");
875 + String password = attributes.getProperty("password", "");
876 + session.put("driver", driver);
877 + session.put("url", url);
878 + session.put("user", user);
879 + boolean isH2 = url.startsWith("jdbc:h2:");
880 + try {
881 + long start = System.currentTimeMillis();
882 + String profOpen = "", profClose = "";
883 + Profiler prof = new Profiler();
884 + prof.startCollecting();
885 + Connection conn;
886 + try {
887 + conn = server.getConnection(driver, url, user, password);
888 + } finally {
889 + prof.stopCollecting();
890 + profOpen = prof.getTop(3);
891 + }
892 + prof = new Profiler();
893 + prof.startCollecting();
894 + try {
895 + JdbcUtils.closeSilently(conn);
896 + } finally {
897 + prof.stopCollecting();
898 + profClose = prof.getTop(3);
899 + }
900 + long time = System.currentTimeMillis() - start;
901 + String success;
902 + if (time > 1000) {
903 + success = "<a class=\"error\" href=\"#\" " +
904 + "onclick=\"var x=document.getElementById('prof').style;x." +
905 + "display=x.display==''?'none':'';\">" +
906 + "${text.login.testSuccessful}</a>" +
907 + "<span style=\"display: none;\" id=\"prof\"><br />" +
908 + PageParser.escapeHtml(profOpen) +
909 + "<br />" +
910 + PageParser.escapeHtml(profClose) +
911 + "</span>";
912 + } else {
913 + success = "${text.login.testSuccessful}";
914 + }
915 + session.put("error", success);
916 + // session.put("error", "${text.login.testSuccessful}");
917 + return "login.jsp";
918 + } catch (Exception e) {
919 + session.put("error", getLoginError(e, isH2));
920 + return "login.jsp";
921 + }
922 + }
923 +
924 + /**
925 + * Get the formatted login error message.
926 + *
927 + * @param e the exception
928 + * @param isH2 if the current database is a H2 database
929 + * @return the formatted error message
930 + */
931 + private String getLoginError(Exception e, boolean isH2) {
932 + if (e instanceof JdbcSQLException &&
933 + ((JdbcSQLException) e).getErrorCode() == ErrorCode.CLASS_NOT_FOUND_1) {
934 + return "${text.login.driverNotFound}<br />" + getStackTrace(0, e, isH2);
935 + }
936 + return getStackTrace(0, e, isH2);
937 + }
938 +
939 + private String login() {
940 + String driver = attributes.getProperty("driver", "");
941 + String url = attributes.getProperty("url", "");
942 + String user = attributes.getProperty("user", "");
943 + String password = attributes.getProperty("password", "");
944 + session.put("autoCommit", "checked");
945 + session.put("autoComplete", "1");
946 + session.put("maxrows", "1000");
947 + boolean isH2 = url.startsWith("jdbc:h2:");
948 + try {
949 + Connection conn = server.getConnection(driver, url, user, password);
950 + session.setConnection(conn);
951 + session.put("url", url);
952 + session.put("user", user);
953 + session.remove("error");
954 + settingSave();
955 + return "frame.jsp";
956 + } catch (Exception e) {
957 + session.put("error", getLoginError(e, isH2));
958 + return "login.jsp";
959 + }
960 + }
961 +
962 + private String logout() {
963 + try {
964 + Connection conn = session.getConnection();
965 + session.setConnection(null);
966 + session.remove("conn");
967 + session.remove("result");
968 + session.remove("tables");
969 + session.remove("user");
970 + session.remove("tool");
971 + if (conn != null) {
972 + if (session.getShutdownServerOnDisconnect()) {
973 + server.shutdown();
974 + } else {
975 + conn.close();
976 + }
977 + }
978 + } catch (Exception e) {
979 + trace(e.toString());
980 + }
981 + return "index.do";
982 + }
983 +
984 + private String query() {
985 + String sql = attributes.getProperty("sql").trim();
986 + try {
987 + ScriptReader r = new ScriptReader(new StringReader(sql));
988 + final ArrayList<String> list = New.arrayList();
989 + while (true) {
990 + String s = r.readStatement();
991 + if (s == null) {
992 + break;
993 + }
994 + list.add(s);
995 + }
996 + final Connection conn = session.getConnection();
997 + if (SysProperties.CONSOLE_STREAM && server.getAllowChunked()) {
998 + String page = new String(server.getFile("result.jsp"), Constants.UTF8);
999 + int idx = page.indexOf("${result}");
1000 + // the first element of the list is the header, the last the
1001 + // footer
1002 + list.add(0, page.substring(0, idx));
1003 + list.add(page.substring(idx + "${result}".length()));
1004 + session.put("chunks", new Iterator<String>() {
1005 + private int i;
1006 + @Override
1007 + public boolean hasNext() {
1008 + return i < list.size();
1009 + }
1010 + @Override
1011 + public String next() {
1012 + String s = list.get(i++);
1013 + if (i == 1 || i == list.size()) {
1014 + return s;
1015 + }
1016 + StringBuilder b = new StringBuilder();
1017 + query(conn, s, i - 1, list.size() - 2, b);
1018 + return b.toString();
1019 + }
1020 + @Override
1021 + public void remove() {
1022 + throw new UnsupportedOperationException();
1023 + }
1024 + });
1025 + return "result.jsp";
1026 + }
1027 + String result;
1028 + StringBuilder buff = new StringBuilder();
1029 + for (int i = 0; i < list.size(); i++) {
1030 + String s = list.get(i);
1031 + query(conn, s, i, list.size(), buff);
1032 + }
1033 + result = buff.toString();
1034 + session.put("result", result);
1035 + } catch (Throwable e) {
1036 + session.put("result", getStackTrace(0, e, session.getContents().isH2()));
1037 + }
1038 + return "result.jsp";
1039 + }
1040 +
1041 + /**
1042 + * Execute a query and append the result to the buffer.
1043 + *
1044 + * @param conn the connection
1045 + * @param s the statement
1046 + * @param i the index
1047 + * @param size the number of statements
1048 + * @param buff the target buffer
1049 + */
1050 + void query(Connection conn, String s, int i, int size, StringBuilder buff) {
1051 + if (!(s.startsWith("@") && s.endsWith("."))) {
1052 + buff.append(PageParser.escapeHtml(s + ";")).append("<br />");
1053 + }
1054 + boolean forceEdit = s.startsWith("@edit");
1055 + buff.append(getResult(conn, i + 1, s, size == 1, forceEdit)).
1056 + append("<br />");
1057 + }
1058 +
1059 + private String editResult() {
1060 + ResultSet rs = session.result;
1061 + int row = Integer.parseInt(attributes.getProperty("row"));
1062 + int op = Integer.parseInt(attributes.getProperty("op"));
1063 + String result = "", error = "";
1064 + try {
1065 + if (op == 1) {
1066 + boolean insert = row < 0;
1067 + if (insert) {
1068 + rs.moveToInsertRow();
1069 + } else {
1070 + rs.absolute(row);
1071 + }
1072 + for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
1073 + String x = attributes.getProperty("r" + row + "c" + (i + 1));
1074 + unescapeData(x, rs, i + 1);
1075 + }
1076 + if (insert) {
1077 + rs.insertRow();
1078 + } else {
1079 + rs.updateRow();
1080 + }
1081 + } else if (op == 2) {
1082 + rs.absolute(row);
1083 + rs.deleteRow();
1084 + } else if (op == 3) {
1085 + // cancel
1086 + }
1087 + } catch (Throwable e) {
1088 + result = "<br />" + getStackTrace(0, e, session.getContents().isH2());
1089 + error = formatAsError(e.getMessage());
1090 + }
1091 + String sql = "@edit " + (String) session.get("resultSetSQL");
1092 + Connection conn = session.getConnection();
1093 + result = error + getResult(conn, -1, sql, true, true) + result;
1094 + session.put("result", result);
1095 + return "result.jsp";
1096 + }
1097 +
1098 + private ResultSet getMetaResultSet(Connection conn, String sql)
1099 + throws SQLException {
1100 + DatabaseMetaData meta = conn.getMetaData();
1101 + if (isBuiltIn(sql, "@best_row_identifier")) {
1102 + String[] p = split(sql);
1103 + int scale = p[4] == null ? 0 : Integer.parseInt(p[4]);
1104 + boolean nullable = p[5] == null ? false : Boolean.parseBoolean(p[5]);
1105 + return meta.getBestRowIdentifier(p[1], p[2], p[3], scale, nullable);
1106 + } else if (isBuiltIn(sql, "@catalogs")) {
1107 + return meta.getCatalogs();
1108 + } else if (isBuiltIn(sql, "@columns")) {
1109 + String[] p = split(sql);
1110 + return meta.getColumns(p[1], p[2], p[3], p[4]);
1111 + } else if (isBuiltIn(sql, "@column_privileges")) {
1112 + String[] p = split(sql);
1113 + return meta.getColumnPrivileges(p[1], p[2], p[3], p[4]);
1114 + } else if (isBuiltIn(sql, "@cross_references")) {
1115 + String[] p = split(sql);
1116 + return meta.getCrossReference(p[1], p[2], p[3], p[4], p[5], p[6]);
1117 + } else if (isBuiltIn(sql, "@exported_keys")) {
1118 + String[] p = split(sql);
1119 + return meta.getExportedKeys(p[1], p[2], p[3]);
1120 + } else if (isBuiltIn(sql, "@imported_keys")) {
1121 + String[] p = split(sql);
1122 + return meta.getImportedKeys(p[1], p[2], p[3]);
1123 + } else if (isBuiltIn(sql, "@index_info")) {
1124 + String[] p = split(sql);
1125 + boolean unique = p[4] == null ? false : Boolean.parseBoolean(p[4]);
1126 + boolean approx = p[5] == null ? false : Boolean.parseBoolean(p[5]);
1127 + return meta.getIndexInfo(p[1], p[2], p[3], unique, approx);
1128 + } else if (isBuiltIn(sql, "@primary_keys")) {
1129 + String[] p = split(sql);
1130 + return meta.getPrimaryKeys(p[1], p[2], p[3]);
1131 + } else if (isBuiltIn(sql, "@procedures")) {
1132 + String[] p = split(sql);
1133 + return meta.getProcedures(p[1], p[2], p[3]);
1134 + } else if (isBuiltIn(sql, "@procedure_columns")) {
1135 + String[] p = split(sql);
1136 + return meta.getProcedureColumns(p[1], p[2], p[3], p[4]);
1137 + } else if (isBuiltIn(sql, "@schemas")) {
1138 + return meta.getSchemas();
1139 + } else if (isBuiltIn(sql, "@tables")) {
1140 + String[] p = split(sql);
1141 + String[] types = p[4] == null ? null : StringUtils.arraySplit(p[4], ',', false);
1142 + return meta.getTables(p[1], p[2], p[3], types);
1143 + } else if (isBuiltIn(sql, "@table_privileges")) {
1144 + String[] p = split(sql);
1145 + return meta.getTablePrivileges(p[1], p[2], p[3]);
1146 + } else if (isBuiltIn(sql, "@table_types")) {
1147 + return meta.getTableTypes();
1148 + } else if (isBuiltIn(sql, "@type_info")) {
1149 + return meta.getTypeInfo();
1150 + } else if (isBuiltIn(sql, "@udts")) {
1151 + String[] p = split(sql);
1152 + int[] types;
1153 + if (p[4] == null) {
1154 + types = null;
1155 + } else {
1156 + String[] t = StringUtils.arraySplit(p[4], ',', false);
1157 + types = new int[t.length];
1158 + for (int i = 0; i < t.length; i++) {
1159 + types[i] = Integer.parseInt(t[i]);
1160 + }
1161 + }
1162 + return meta.getUDTs(p[1], p[2], p[3], types);
1163 + } else if (isBuiltIn(sql, "@version_columns")) {
1164 + String[] p = split(sql);
1165 + return meta.getVersionColumns(p[1], p[2], p[3]);
1166 + } else if (isBuiltIn(sql, "@memory")) {
1167 + SimpleResultSet rs = new SimpleResultSet();
1168 + rs.addColumn("Type", Types.VARCHAR, 0, 0);
1169 + rs.addColumn("KB", Types.VARCHAR, 0, 0);
1170 + rs.addRow("Used Memory", "" + Utils.getMemoryUsed());
1171 + rs.addRow("Free Memory", "" + Utils.getMemoryFree());
1172 + return rs;
1173 + } else if (isBuiltIn(sql, "@info")) {
1174 + SimpleResultSet rs = new SimpleResultSet();
1175 + rs.addColumn("KEY", Types.VARCHAR, 0, 0);
1176 + rs.addColumn("VALUE", Types.VARCHAR, 0, 0);
1177 + rs.addRow("conn.getCatalog", conn.getCatalog());
1178 + rs.addRow("conn.getAutoCommit", "" + conn.getAutoCommit());
1179 + rs.addRow("conn.getTransactionIsolation", "" + conn.getTransactionIsolation());
1180 + rs.addRow("conn.getWarnings", "" + conn.getWarnings());
1181 + String map;
1182 + try {
1183 + map = "" + conn.getTypeMap();
1184 + } catch (SQLException e) {
1185 + map = e.toString();
1186 + }
1187 + rs.addRow("conn.getTypeMap", "" + map);
1188 + rs.addRow("conn.isReadOnly", "" + conn.isReadOnly());
1189 + rs.addRow("conn.getHoldability", "" + conn.getHoldability());
1190 + addDatabaseMetaData(rs, meta);
1191 + return rs;
1192 + } else if (isBuiltIn(sql, "@attributes")) {
1193 + String[] p = split(sql);
1194 + return meta.getAttributes(p[1], p[2], p[3], p[4]);
1195 + } else if (isBuiltIn(sql, "@super_tables")) {
1196 + String[] p = split(sql);
1197 + return meta.getSuperTables(p[1], p[2], p[3]);
1198 + } else if (isBuiltIn(sql, "@super_types")) {
1199 + String[] p = split(sql);
1200 + return meta.getSuperTypes(p[1], p[2], p[3]);
1201 + } else if (isBuiltIn(sql, "@prof_stop")) {
1202 + if (profiler != null) {
1203 + profiler.stopCollecting();
1204 + SimpleResultSet rs = new SimpleResultSet();
1205 + rs.addColumn("Top Stack Trace(s)", Types.VARCHAR, 0, 0);
1206 + rs.addRow(profiler.getTop(3));
1207 + profiler = null;
1208 + return rs;
1209 + }
1210 + }
1211 + return null;
1212 + }
1213 +
1214 + private static void addDatabaseMetaData(SimpleResultSet rs,
1215 + DatabaseMetaData meta) {
1216 + Method[] methods = DatabaseMetaData.class.getDeclaredMethods();
1217 + Arrays.sort(methods, new Comparator<Method>() {
1218 + @Override
1219 + public int compare(Method o1, Method o2) {
1220 + return o1.toString().compareTo(o2.toString());
1221 + }
1222 + });
1223 + for (Method m : methods) {
1224 + if (m.getParameterTypes().length == 0) {
1225 + try {
1226 + Object o = m.invoke(meta);
1227 + rs.addRow("meta." + m.getName(), "" + o);
1228 + } catch (InvocationTargetException e) {
1229 + rs.addRow("meta." + m.getName(), e.getTargetException().toString());
1230 + } catch (Exception e) {
1231 + rs.addRow("meta." + m.getName(), e.toString());
1232 + }
1233 + }
1234 + }
1235 + }
1236 +
1237 + private static String[] split(String s) {
1238 + String[] list = new String[10];
1239 + String[] t = StringUtils.arraySplit(s, ' ', true);
1240 + System.arraycopy(t, 0, list, 0, t.length);
1241 + for (int i = 0; i < list.length; i++) {
1242 + if ("null".equals(list[i])) {
1243 + list[i] = null;
1244 + }
1245 + }
1246 + return list;
1247 + }
1248 +
1249 + private int getMaxrows() {
1250 + String r = (String) session.get("maxrows");
1251 + int maxrows = r == null ? 0 : Integer.parseInt(r);
1252 + return maxrows;
1253 + }
1254 +
1255 + private String getResult(Connection conn, int id, String sql,
1256 + boolean allowEdit, boolean forceEdit) {
1257 + try {
1258 + sql = sql.trim();
1259 + StringBuilder buff = new StringBuilder();
1260 + String sqlUpper = StringUtils.toUpperEnglish(sql);
1261 + if (sqlUpper.contains("CREATE") ||
1262 + sqlUpper.contains("DROP") ||
1263 + sqlUpper.contains("ALTER") ||
1264 + sqlUpper.contains("RUNSCRIPT")) {
1265 + String sessionId = attributes.getProperty("jsessionid");
1266 + buff.append("<script type=\"text/javascript\">" +
1267 + "parent['h2menu'].location='tables.do?jsessionid="
1268 + + sessionId + "';</script>");
1269 + }
1270 + Statement stat;
1271 + DbContents contents = session.getContents();
1272 + if (forceEdit || (allowEdit && contents.isH2())) {
1273 + stat = conn.createStatement(
1274 + ResultSet.TYPE_SCROLL_INSENSITIVE,
1275 + ResultSet.CONCUR_UPDATABLE);
1276 + } else {
1277 + stat = conn.createStatement();
1278 + }
1279 + ResultSet rs;
1280 + long time = System.currentTimeMillis();
1281 + boolean metadata = false;
1282 + boolean generatedKeys = false;
1283 + boolean edit = false;
1284 + boolean list = false;
1285 + if (isBuiltIn(sql, "@autocommit_true")) {
1286 + conn.setAutoCommit(true);
1287 + return "${text.result.autoCommitOn}";
1288 + } else if (isBuiltIn(sql, "@autocommit_false")) {
1289 + conn.setAutoCommit(false);
1290 + return "${text.result.autoCommitOff}";
1291 + } else if (isBuiltIn(sql, "@cancel")) {
1292 + stat = session.executingStatement;
1293 + if (stat != null) {
1294 + stat.cancel();
1295 + buff.append("${text.result.statementWasCanceled}");
1296 + } else {
1297 + buff.append("${text.result.noRunningStatement}");
1298 + }
1299 + return buff.toString();
1300 + } else if (isBuiltIn(sql, "@edit")) {
1301 + edit = true;
1302 + sql = sql.substring("@edit".length()).trim();
1303 + session.put("resultSetSQL", sql);
1304 + }
1305 + if (isBuiltIn(sql, "@list")) {
1306 + list = true;
1307 + sql = sql.substring("@list".length()).trim();
1308 + }
1309 + if (isBuiltIn(sql, "@meta")) {
1310 + metadata = true;
1311 + sql = sql.substring("@meta".length()).trim();
1312 + }
1313 + if (isBuiltIn(sql, "@generated")) {
1314 + generatedKeys = true;
1315 + sql = sql.substring("@generated".length()).trim();
1316 + } else if (isBuiltIn(sql, "@history")) {
1317 + buff.append(getCommandHistoryString());
1318 + return buff.toString();
1319 + } else if (isBuiltIn(sql, "@loop")) {
1320 + sql = sql.substring("@loop".length()).trim();
1321 + int idx = sql.indexOf(' ');
1322 + int count = Integer.decode(sql.substring(0, idx));
1323 + sql = sql.substring(idx).trim();
1324 + return executeLoop(conn, count, sql);
1325 + } else if (isBuiltIn(sql, "@maxrows")) {
1326 + int maxrows = (int) Double.parseDouble(
1327 + sql.substring("@maxrows".length()).trim());
1328 + session.put("maxrows", "" + maxrows);
1329 + return "${text.result.maxrowsSet}";
1330 + } else if (isBuiltIn(sql, "@parameter_meta")) {
1331 + sql = sql.substring("@parameter_meta".length()).trim();
1332 + PreparedStatement prep = conn.prepareStatement(sql);
1333 + buff.append(getParameterResultSet(prep.getParameterMetaData()));
1334 + return buff.toString();
1335 + } else if (isBuiltIn(sql, "@password_hash")) {
1336 + sql = sql.substring("@password_hash".length()).trim();
1337 + String[] p = split(sql);
1338 + return StringUtils.convertBytesToHex(
1339 + SHA256.getKeyPasswordHash(p[0], p[1].toCharArray()));
1340 + } else if (isBuiltIn(sql, "@prof_start")) {
1341 + if (profiler != null) {
1342 + profiler.stopCollecting();
1343 + }
1344 + profiler = new Profiler();
1345 + profiler.startCollecting();
1346 + return "Ok";
1347 + } else if (isBuiltIn(sql, "@sleep")) {
1348 + String s = sql.substring("@sleep".length()).trim();
1349 + int sleep = 1;
1350 + if (s.length() > 0) {
1351 + sleep = Integer.parseInt(s);
1352 + }
1353 + Thread.sleep(sleep * 1000);
1354 + return "Ok";
1355 + } else if (isBuiltIn(sql, "@transaction_isolation")) {
1356 + String s = sql.substring("@transaction_isolation".length()).trim();
1357 + if (s.length() > 0) {
1358 + int level = Integer.parseInt(s);
1359 + conn.setTransactionIsolation(level);
1360 + }
1361 + buff.append("Transaction Isolation: " +
1362 + conn.getTransactionIsolation() + "<br />");
1363 + buff.append(Connection.TRANSACTION_READ_UNCOMMITTED +
1364 + ": read_uncommitted<br />");
1365 + buff.append(Connection.TRANSACTION_READ_COMMITTED +
1366 + ": read_committed<br />");
1367 + buff.append(Connection.TRANSACTION_REPEATABLE_READ +
1368 + ": repeatable_read<br />");
1369 + buff.append(Connection.TRANSACTION_SERIALIZABLE +
1370 + ": serializable");
1371 + }
1372 + if (sql.startsWith("@")) {
1373 + rs = getMetaResultSet(conn, sql);
1374 + if (rs == null) {
1375 + buff.append("?: " + sql);
1376 + return buff.toString();
1377 + }
1378 + } else {
1379 + int maxrows = getMaxrows();
1380 + stat.setMaxRows(maxrows);
1381 + session.executingStatement = stat;
1382 + boolean isResultSet = stat.execute(sql);
1383 + session.addCommand(sql);
1384 + if (generatedKeys) {
1385 + rs = null;
1386 + rs = stat.getGeneratedKeys();
1387 + } else {
1388 + if (!isResultSet) {
1389 + buff.append("${text.result.updateCount}: " + stat.getUpdateCount());
1390 + time = System.currentTimeMillis() - time;
1391 + buff.append("<br />(").append(time).append(" ms)");
1392 + stat.close();
1393 + return buff.toString();
1394 + }
1395 + rs = stat.getResultSet();
1396 + }
1397 + }
1398 + time = System.currentTimeMillis() - time;
1399 + buff.append(getResultSet(sql, rs, metadata, list, edit, time, allowEdit));
1400 + // SQLWarning warning = stat.getWarnings();
1401 + // if (warning != null) {
1402 + // buff.append("<br />Warning:<br />").
1403 + // append(getStackTrace(id, warning));
1404 + // }
1405 + if (!edit) {
1406 + stat.close();
1407 + }
1408 + return buff.toString();
1409 + } catch (Throwable e) {
1410 + // throwable: including OutOfMemoryError and so on
1411 + return getStackTrace(id, e, session.getContents().isH2());
1412 + } finally {
1413 + session.executingStatement = null;
1414 + }
1415 + }
1416 +
1417 + private static boolean isBuiltIn(String sql, String builtIn) {
1418 + return StringUtils.startsWithIgnoreCase(sql, builtIn);
1419 + }
1420 +
1421 + private String executeLoop(Connection conn, int count, String sql)
1422 + throws SQLException {
1423 + ArrayList<Integer> params = New.arrayList();
1424 + int idx = 0;
1425 + while (!stop) {
1426 + idx = sql.indexOf('?', idx);
1427 + if (idx < 0) {
1428 + break;
1429 + }
1430 + if (isBuiltIn(sql.substring(idx), "?/*rnd*/")) {
1431 + params.add(1);
1432 + sql = sql.substring(0, idx) + "?" + sql.substring(idx + "/*rnd*/".length() + 1);
1433 + } else {
1434 + params.add(0);
1435 + }
1436 + idx++;
1437 + }
1438 + boolean prepared;
1439 + Random random = new Random(1);
1440 + long time = System.currentTimeMillis();
1441 + if (isBuiltIn(sql, "@statement")) {
1442 + sql = sql.substring("@statement".length()).trim();
1443 + prepared = false;
1444 + Statement stat = conn.createStatement();
1445 + for (int i = 0; !stop && i < count; i++) {
1446 + String s = sql;
1447 + for (Integer type : params) {
1448 + idx = s.indexOf('?');
1449 + if (type.intValue() == 1) {
1450 + s = s.substring(0, idx) + random.nextInt(count) + s.substring(idx + 1);
1451 + } else {
1452 + s = s.substring(0, idx) + i + s.substring(idx + 1);
1453 + }
1454 + }
1455 + if (stat.execute(s)) {
1456 + ResultSet rs = stat.getResultSet();
1457 + while (!stop && rs.next()) {
1458 + // maybe get the data as well
1459 + }
1460 + rs.close();
1461 + }
1462 + }
1463 + } else {
1464 + prepared = true;
1465 + PreparedStatement prep = conn.prepareStatement(sql);
1466 + for (int i = 0; !stop && i < count; i++) {
1467 + for (int j = 0; j < params.size(); j++) {
1468 + Integer type = params.get(j);
1469 + if (type.intValue() == 1) {
1470 + prep.setInt(j + 1, random.nextInt(count));
1471 + } else {
1472 + prep.setInt(j + 1, i);
1473 + }
1474 + }
1475 + if (session.getContents().isSQLite()) {
1476 + // SQLite currently throws an exception on prep.execute()
1477 + prep.executeUpdate();
1478 + } else {
1479 + if (prep.execute()) {
1480 + ResultSet rs = prep.getResultSet();
1481 + while (!stop && rs.next()) {
1482 + // maybe get the data as well
1483 + }
1484 + rs.close();
1485 + }
1486 + }
1487 + }
1488 + }
1489 + time = System.currentTimeMillis() - time;
1490 + StatementBuilder buff = new StatementBuilder();
1491 + buff.append(time).append(" ms: ").append(count).append(" * ");
1492 + if (prepared) {
1493 + buff.append("(Prepared) ");
1494 + } else {
1495 + buff.append("(Statement) ");
1496 + }
1497 + buff.append('(');
1498 + for (int p : params) {
1499 + buff.appendExceptFirst(", ");
1500 + buff.append(p == 0 ? "i" : "rnd");
1501 + }
1502 + return buff.append(") ").append(sql).toString();
1503 + }
1504 +
1505 + private String getCommandHistoryString() {
1506 + StringBuilder buff = new StringBuilder();
1507 + ArrayList<String> history = session.getCommandHistory();
1508 + buff.append("<table cellspacing=0 cellpadding=0>" +
1509 + "<tr><th></th><th>Command</th></tr>");
1510 + for (int i = history.size() - 1; i >= 0; i--) {
1511 + String sql = history.get(i);
1512 + buff.append("<tr><td><a href=\"getHistory.do?id=").
1513 + append(i).
1514 + append("&jsessionid=${sessionId}\" target=\"h2query\" >").
1515 + append("<img width=16 height=16 src=\"ico_write.gif\" " +
1516 + "onmouseover = \"this.className ='icon_hover'\" ").
1517 + append("onmouseout = \"this.className ='icon'\" " +
1518 + "class=\"icon\" alt=\"${text.resultEdit.edit}\" ").
1519 + append("title=\"${text.resultEdit.edit}\" border=\"1\"/></a>").
1520 + append("</td><td>").
1521 + append(PageParser.escapeHtml(sql)).
1522 + append("</td></tr>");
1523 + }
1524 + buff.append("</table>");
1525 + return buff.toString();
1526 + }
1527 +
1528 + private static String getParameterResultSet(ParameterMetaData meta)
1529 + throws SQLException {
1530 + StringBuilder buff = new StringBuilder();
1531 + if (meta == null) {
1532 + return "No parameter meta data";
1533 + }
1534 + buff.append("<table cellspacing=0 cellpadding=0>").
1535 + append("<tr><th>className</th><th>mode</th><th>type</th>").
1536 + append("<th>typeName</th><th>precision</th><th>scale</th></tr>");
1537 + for (int i = 0; i < meta.getParameterCount(); i++) {
1538 + buff.append("</tr><td>").
1539 + append(meta.getParameterClassName(i + 1)).
1540 + append("</td><td>").
1541 + append(meta.getParameterMode(i + 1)).
1542 + append("</td><td>").
1543 + append(meta.getParameterType(i + 1)).
1544 + append("</td><td>").
1545 + append(meta.getParameterTypeName(i + 1)).
1546 + append("</td><td>").
1547 + append(meta.getPrecision(i + 1)).
1548 + append("</td><td>").
1549 + append(meta.getScale(i + 1)).
1550 + append("</td></tr>");
1551 + }
1552 + buff.append("</table>");
1553 + return buff.toString();
1554 + }
1555 +
1556 + private String getResultSet(String sql, ResultSet rs, boolean metadata,
1557 + boolean list, boolean edit, long time, boolean allowEdit)
1558 + throws SQLException {
1559 + int maxrows = getMaxrows();
1560 + time = System.currentTimeMillis() - time;
1561 + StringBuilder buff = new StringBuilder();
1562 + if (edit) {
1563 + buff.append("<form id=\"editing\" name=\"editing\" method=\"post\" " +
1564 + "action=\"editResult.do?jsessionid=${sessionId}\" " +
1565 + "id=\"mainForm\" target=\"h2result\">" +
1566 + "<input type=\"hidden\" name=\"op\" value=\"1\" />" +
1567 + "<input type=\"hidden\" name=\"row\" value=\"\" />" +
1568 + "<table cellspacing=0 cellpadding=0 id=\"editTable\">");
1569 + } else {
1570 + buff.append("<table cellspacing=0 cellpadding=0>");
1571 + }
1572 + if (metadata) {
1573 + SimpleResultSet r = new SimpleResultSet();
1574 + r.addColumn("#", Types.INTEGER, 0, 0);
1575 + r.addColumn("label", Types.VARCHAR, 0, 0);
1576 + r.addColumn("catalog", Types.VARCHAR, 0, 0);
1577 + r.addColumn("schema", Types.VARCHAR, 0, 0);
1578 + r.addColumn("table", Types.VARCHAR, 0, 0);
1579 + r.addColumn("column", Types.VARCHAR, 0, 0);
1580 + r.addColumn("type", Types.INTEGER, 0, 0);
1581 + r.addColumn("typeName", Types.VARCHAR, 0, 0);
1582 + r.addColumn("class", Types.VARCHAR, 0, 0);
1583 + r.addColumn("precision", Types.INTEGER, 0, 0);
1584 + r.addColumn("scale", Types.INTEGER, 0, 0);
1585 + r.addColumn("displaySize", Types.INTEGER, 0, 0);
1586 + r.addColumn("autoIncrement", Types.BOOLEAN, 0, 0);
1587 + r.addColumn("caseSensitive", Types.BOOLEAN, 0, 0);
1588 + r.addColumn("currency", Types.BOOLEAN, 0, 0);
1589 + r.addColumn("nullable", Types.INTEGER, 0, 0);
1590 + r.addColumn("readOnly", Types.BOOLEAN, 0, 0);
1591 + r.addColumn("searchable", Types.BOOLEAN, 0, 0);
1592 + r.addColumn("signed", Types.BOOLEAN, 0, 0);
1593 + r.addColumn("writable", Types.BOOLEAN, 0, 0);
1594 + r.addColumn("definitelyWritable", Types.BOOLEAN, 0, 0);
1595 + ResultSetMetaData m = rs.getMetaData();
1596 + for (int i = 1; i <= m.getColumnCount(); i++) {
1597 + r.addRow(i,
1598 + m.getColumnLabel(i),
1599 + m.getCatalogName(i),
1600 + m.getSchemaName(i),
1601 + m.getTableName(i),
1602 + m.getColumnName(i),
1603 + m.getColumnType(i),
1604 + m.getColumnTypeName(i),
1605 + m.getColumnClassName(i),
1606 + m.getPrecision(i),
1607 + m.getScale(i),
1608 + m.getColumnDisplaySize(i),
1609 + m.isAutoIncrement(i),
1610 + m.isCaseSensitive(i),
1611 + m.isCurrency(i),
1612 + m.isNullable(i),
1613 + m.isReadOnly(i),
1614 + m.isSearchable(i),
1615 + m.isSigned(i),
1616 + m.isWritable(i),
1617 + m.isDefinitelyWritable(i));
1618 + }
1619 + rs = r;
1620 + }
1621 + ResultSetMetaData meta = rs.getMetaData();
1622 + int columns = meta.getColumnCount();
1623 + int rows = 0;
1624 + if (list) {
1625 + buff.append("<tr><th>Column</th><th>Data</th></tr><tr>");
1626 + while (rs.next()) {
1627 + if (maxrows > 0 && rows >= maxrows) {
1628 + break;
1629 + }
1630 + rows++;
1631 + buff.append("<tr><td>Row #</td><td>").
1632 + append(rows).append("</tr>");
1633 + for (int i = 0; i < columns; i++) {
1634 + buff.append("<tr><td>").
1635 + append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))).
1636 + append("</td><td>").
1637 + append(escapeData(rs, i + 1)).
1638 + append("</td></tr>");
1639 + }
1640 + }
1641 + } else {
1642 + buff.append("<tr>");
1643 + if (edit) {
1644 + buff.append("<th>${text.resultEdit.action}</th>");
1645 + }
1646 + for (int i = 0; i < columns; i++) {
1647 + buff.append("<th>").
1648 + append(PageParser.escapeHtml(meta.getColumnLabel(i + 1))).
1649 + append("</th>");
1650 + }
1651 + buff.append("</tr>");
1652 + while (rs.next()) {
1653 + if (maxrows > 0 && rows >= maxrows) {
1654 + break;
1655 + }
1656 + rows++;
1657 + buff.append("<tr>");
1658 + if (edit) {
1659 + buff.append("<td>").
1660 + append("<img onclick=\"javascript:editRow(").
1661 + append(rs.getRow()).
1662 + append(",'${sessionId}', '${text.resultEdit.save}', " +
1663 + "'${text.resultEdit.cancel}'").
1664 + append(")\" width=16 height=16 src=\"ico_write.gif\" " +
1665 + "onmouseover = \"this.className ='icon_hover'\" " +
1666 + "onmouseout = \"this.className ='icon'\" " +
1667 + "class=\"icon\" alt=\"${text.resultEdit.edit}\" " +
1668 + "title=\"${text.resultEdit.edit}\" border=\"1\"/>").
1669 + append("<a href=\"editResult.do?op=2&row=").
1670 + append(rs.getRow()).
1671 + append("&jsessionid=${sessionId}\" target=\"h2result\" >" +
1672 + "<img width=16 height=16 src=\"ico_remove.gif\" " +
1673 + "onmouseover = \"this.className ='icon_hover'\" " +
1674 + "onmouseout = \"this.className ='icon'\" " +
1675 + "class=\"icon\" alt=\"${text.resultEdit.delete}\" " +
1676 + "title=\"${text.resultEdit.delete}\" border=\"1\" /></a>").
1677 + append("</td>");
1678 + }
1679 + for (int i = 0; i < columns; i++) {
1680 + buff.append("<td>").
1681 + append(escapeData(rs, i + 1)).
1682 + append("</td>");
1683 + }
1684 + buff.append("</tr>");
1685 + }
1686 + }
1687 + boolean isUpdatable = false;
1688 + try {
1689 + if (!session.getContents().isDB2()) {
1690 + isUpdatable = rs.getConcurrency() == ResultSet.CONCUR_UPDATABLE
1691 + && rs.getType() != ResultSet.TYPE_FORWARD_ONLY;
1692 + }
1693 + } catch (NullPointerException e) {
1694 + // ignore
1695 + // workaround for a JDBC-ODBC bridge problem
1696 + }
1697 + if (edit) {
1698 + ResultSet old = session.result;
1699 + if (old != null) {
1700 + old.close();
1701 + }
1702 + session.result = rs;
1703 + } else {
1704 + rs.close();
1705 + }
1706 + if (edit) {
1707 + buff.append("<tr><td>").
1708 + append("<img onclick=\"javascript:editRow(-1, " +
1709 + "'${sessionId}', '${text.resultEdit.save}', '${text.resultEdit.cancel}'").
1710 + append(")\" width=16 height=16 src=\"ico_add.gif\" " +
1711 + "onmouseover = \"this.className ='icon_hover'\" " +
1712 + "onmouseout = \"this.className ='icon'\" " +
1713 + "class=\"icon\" alt=\"${text.resultEdit.add}\" " +
1714 + "title=\"${text.resultEdit.add}\" border=\"1\"/>").
1715 + append("</td>");
1716 + for (int i = 0; i < columns; i++) {
1717 + buff.append("<td></td>");
1718 + }
1719 + buff.append("</tr>");
1720 + }
1721 + buff.append("</table>");
1722 + if (edit) {
1723 + buff.append("</form>");
1724 + }
1725 + if (rows == 0) {
1726 + buff.append("(${text.result.noRows}");
1727 + } else if (rows == 1) {
1728 + buff.append("(${text.result.1row}");
1729 + } else {
1730 + buff.append('(').append(rows).append(" ${text.result.rows}");
1731 + }
1732 + buff.append(", ");
1733 + time = System.currentTimeMillis() - time;
1734 + buff.append(time).append(" ms)");
1735 + if (!edit && isUpdatable && allowEdit) {
1736 + buff.append("<br /><br />" +
1737 + "<form name=\"editResult\" method=\"post\" " +
1738 + "action=\"query.do?jsessionid=${sessionId}\" target=\"h2result\">" +
1739 + "<input type=\"submit\" class=\"button\" " +
1740 + "value=\"${text.resultEdit.editResult}\" />" +
1741 + "<input type=\"hidden\" name=\"sql\" value=\"@edit ").
1742 + append(PageParser.escapeHtmlData(sql)).
1743 + append("\" /></form>");
1744 + }
1745 + return buff.toString();
1746 + }
1747 +
1748 + /**
1749 + * Save the current connection settings to the properties file.
1750 + *
1751 + * @return the file to open afterwards
1752 + */
1753 + private String settingSave() {
1754 + ConnectionInfo info = new ConnectionInfo();
1755 + info.name = attributes.getProperty("name", "");
1756 + info.driver = attributes.getProperty("driver", "");
1757 + info.url = attributes.getProperty("url", "");
1758 + info.user = attributes.getProperty("user", "");
1759 + server.updateSetting(info);
1760 + attributes.put("setting", info.name);
1761 + server.saveProperties(null);
1762 + return "index.do";
1763 + }
1764 +
1765 + private static String escapeData(ResultSet rs, int columnIndex)
1766 + throws SQLException {
1767 + String d = rs.getString(columnIndex);
1768 + if (d == null) {
1769 + return "<i>null</i>";
1770 + } else if (d.length() > 100000) {
1771 + String s;
1772 + if (isBinary(rs.getMetaData().getColumnType(columnIndex))) {
1773 + s = PageParser.escapeHtml(d.substring(0, 6)) +
1774 + "... (" + (d.length() / 2) + " ${text.result.bytes})";
1775 + } else {
1776 + s = PageParser.escapeHtml(d.substring(0, 100)) +
1777 + "... (" + d.length() + " ${text.result.characters})";
1778 + }
1779 + return "<div style='display: none'>=+</div>" + s;
1780 + } else if (d.equals("null") || d.startsWith("= ") || d.startsWith("=+")) {
1781 + return "<div style='display: none'>= </div>" + PageParser.escapeHtml(d);
1782 + } else if (d.equals("")) {
1783 + // PageParser.escapeHtml replaces "" with a non-breaking space
1784 + return "";
1785 + }
1786 + return PageParser.escapeHtml(d);
1787 + }
1788 +
1789 + private static boolean isBinary(int sqlType) {
1790 + switch (sqlType) {
1791 + case Types.BINARY:
1792 + case Types.BLOB:
1793 + case Types.JAVA_OBJECT:
1794 + case Types.LONGVARBINARY:
1795 + case Types.OTHER:
1796 + case Types.VARBINARY:
1797 + return true;
1798 + }
1799 + return false;
1800 + }
1801 +
1802 + private void unescapeData(String x, ResultSet rs, int columnIndex)
1803 + throws SQLException {
1804 + if (x.equals("null")) {
1805 + rs.updateNull(columnIndex);
1806 + return;
1807 + } else if (x.startsWith("=+")) {
1808 + // don't update
1809 + return;
1810 + } else if (x.equals("=*")) {
1811 + // set an appropriate default value
1812 + int type = rs.getMetaData().getColumnType(columnIndex);
1813 + switch (type) {
1814 + case Types.TIME:
1815 + rs.updateString(columnIndex, "12:00:00");
1816 + break;
1817 + case Types.TIMESTAMP:
1818 + case Types.DATE:
1819 + rs.updateString(columnIndex, "2001-01-01");
1820 + break;
1821 + default:
1822 + rs.updateString(columnIndex, "1");
1823 + break;
1824 + }
1825 + return;
1826 + } else if (x.startsWith("= ")) {
1827 + x = x.substring(2);
1828 + }
1829 + ResultSetMetaData meta = rs.getMetaData();
1830 + int type = meta.getColumnType(columnIndex);
1831 + if (session.getContents().isH2()) {
1832 + rs.updateString(columnIndex, x);
1833 + return;
1834 + }
1835 + switch (type) {
1836 + case Types.BIGINT:
1837 + rs.updateLong(columnIndex, Long.decode(x));
1838 + break;
1839 + case Types.DECIMAL:
1840 + rs.updateBigDecimal(columnIndex, new BigDecimal(x));
1841 + break;
1842 + case Types.DOUBLE:
1843 + case Types.FLOAT:
1844 + rs.updateDouble(columnIndex, Double.parseDouble(x));
1845 + break;
1846 + case Types.REAL:
1847 + rs.updateFloat(columnIndex, Float.parseFloat(x));
1848 + break;
1849 + case Types.INTEGER:
1850 + rs.updateInt(columnIndex, Integer.decode(x));
1851 + break;
1852 + case Types.TINYINT:
1853 + rs.updateShort(columnIndex, Short.decode(x));
1854 + break;
1855 + default:
1856 + rs.updateString(columnIndex, x);
1857 + }
1858 + }
1859 +
1860 + private String settingRemove() {
1861 + String setting = attributes.getProperty("name", "");
1862 + server.removeSetting(setting);
1863 + ArrayList<ConnectionInfo> settings = server.getSettings();
1864 + if (settings.size() > 0) {
1865 + attributes.put("setting", settings.get(0));
1866 + }
1867 + server.saveProperties(null);
1868 + return "index.do";
1869 + }
1870 +
1871 + /**
1872 + * Get the current mime type.
1873 + *
1874 + * @return the mime type
1875 + */
1876 + String getMimeType() {
1877 + return mimeType;
1878 + }
1879 +
1880 + boolean getCache() {
1881 + return cache;
1882 + }
1883 +
1884 + WebSession getSession() {
1885 + return session;
1886 + }
1887 +
1888 + private void trace(String s) {
1889 + server.trace(s);
1890 + }
1891 +
1892 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.legrog.util;
2 +// Code copied from org.h2.server.web.WebServer
3 +/*
4 + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
5 + * and the EPL 1.0 (http://h2database.com/html/license.html).
6 + * Initial Developer: H2 Group
7 + */
8 +//package org.h2.server.web;
9 +
10 + import java.io.File;
11 + import java.io.IOException;
12 + import java.io.InputStream;
13 + import java.io.OutputStream;
14 + import java.net.ServerSocket;
15 + import java.net.Socket;
16 + import java.sql.Connection;
17 + import java.sql.SQLException;
18 + import java.text.SimpleDateFormat;
19 + import java.util.ArrayList;
20 + import java.util.Collections;
21 + import java.util.HashMap;
22 + import java.util.HashSet;
23 + import java.util.Locale;
24 + import java.util.Map;
25 + import java.util.Map.Entry;
26 + import java.util.Properties;
27 + import java.util.Set;
28 + import java.util.TimeZone;
29 +
30 + import org.h2.engine.Constants;
31 + import org.h2.engine.SysProperties;
32 + import org.h2.message.DbException;
33 + import org.h2.server.Service;
34 + import org.h2.server.ShutdownHandler;
35 + import org.h2.store.fs.FileUtils;
36 + import org.h2.util.JdbcUtils;
37 + import org.h2.util.MathUtils;
38 + import org.h2.util.NetUtils;
39 + import org.h2.util.New;
40 + import org.h2.util.SortedProperties;
41 + import org.h2.util.StringUtils;
42 + import org.h2.util.Tool;
43 + import org.h2.util.Utils;
44 +
45 +/**
46 + * The web server is a simple standalone HTTP server that implements the H2
47 + * Console application. It is not optimized for performance.
48 + */
49 +public class WebServer implements Service {
50 +
51 + static final String[][] LANGUAGES = {
52 + { "cs", "\u010ce\u0161tina" },
53 + { "de", "Deutsch" },
54 + { "en", "English" },
55 + { "es", "Espa\u00f1ol" },
56 + { "fr", "Fran\u00e7ais" },
57 + { "hu", "Magyar"},
58 + { "ko", "\ud55c\uad6d\uc5b4"},
59 + { "in", "Indonesia"},
60 + { "it", "Italiano"},
61 + { "ja", "\u65e5\u672c\u8a9e"},
62 + { "nl", "Nederlands"},
63 + { "pl", "Polski"},
64 + { "pt_BR", "Portugu\u00eas (Brasil)"},
65 + { "pt_PT", "Portugu\u00eas (Europeu)"},
66 + { "ru", "\u0440\u0443\u0441\u0441\u043a\u0438\u0439"},
67 + { "sk", "Slovensky"},
68 + { "tr", "T\u00fcrk\u00e7e"},
69 + { "uk", "\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"},
70 + { "zh_CN", "\u4e2d\u6587 (\u7b80\u4f53)"},
71 + { "zh_TW", "\u4e2d\u6587 (\u7e41\u9ad4)"},
72 + };
73 +
74 + private static final String COMMAND_HISTORY = "commandHistory";
75 +
76 + private static final String DEFAULT_LANGUAGE = "en";
77 +
78 + private static final String[] GENERIC = {
79 + "Generic JNDI Data Source|javax.naming.InitialContext|" +
80 + "java:comp/env/jdbc/Test|sa",
81 + "Generic Firebird Server|org.firebirdsql.jdbc.FBDriver|" +
82 + "jdbc:firebirdsql:localhost:c:/temp/firebird/test|sysdba",
83 + "Generic SQLite|org.sqlite.JDBC|" +
84 + "jdbc:sqlite:test|sa",
85 + "Generic DB2|com.ibm.db2.jcc.DB2Driver|" +
86 + "jdbc:db2://localhost/test|" ,
87 + "Generic Oracle|oracle.jdbc.driver.OracleDriver|" +
88 + "jdbc:oracle:thin:@localhost:1521:XE|sa" ,
89 + "Generic MS SQL Server 2000|com.microsoft.jdbc.sqlserver.SQLServerDriver|" +
90 + "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=sqlexpress|sa",
91 + "Generic MS SQL Server 2005|com.microsoft.sqlserver.jdbc.SQLServerDriver|" +
92 + "jdbc:sqlserver://localhost;DatabaseName=test|sa",
93 + "Generic PostgreSQL|org.postgresql.Driver|" +
94 + "jdbc:postgresql:test|" ,
95 + "Generic MySQL|com.mysql.jdbc.Driver|" +
96 + "jdbc:mysql://localhost:3306/test|" ,
97 + "Generic HSQLDB|org.hsqldb.jdbcDriver|" +
98 + "jdbc:hsqldb:test;hsqldb.default_table_type=cached|sa" ,
99 + "Generic Derby (Server)|org.apache.derby.jdbc.ClientDriver|" +
100 + "jdbc:derby://localhost:1527/test;create=true|sa",
101 + "Generic Derby (Embedded)|org.apache.derby.jdbc.EmbeddedDriver|" +
102 + "jdbc:derby:test;create=true|sa",
103 + "Generic H2 (Server)|org.h2.Driver|" +
104 + "jdbc:h2:tcp://localhost/~/test|sa",
105 + // this will be listed on top for new installations
106 + "Generic H2 (Embedded)|org.h2.Driver|" +
107 + "jdbc:h2:~/test|sa",
108 + };
109 +
110 + private static int ticker;
111 +
112 + /**
113 + * The session timeout (the default is 30 minutes).
114 + */
115 + private static final long SESSION_TIMEOUT = SysProperties.CONSOLE_TIMEOUT;
116 +
117 +// public static void main(String... args) throws IOException {
118 +// String s = IOUtils.readStringAndClose(new java.io.FileReader(
119 +// // "src/main/org/h2/server/web/res/_text_cs.prop"), -1);
120 +// "src/main/org/h2/res/_messages_cs.prop"), -1);
121 +// System.out.println(StringUtils.javaEncode("..."));
122 +// String[] list = Locale.getISOLanguages();
123 +// for (int i = 0; i < list.length; i++) {
124 +// System.out.print(list[i] + " ");
125 +// }
126 +// System.out.println();
127 +// String l = "de";
128 +// String lang = new java.util.Locale(l).
129 +// getDisplayLanguage(new java.util.Locale(l));
130 +// System.out.println(new java.util.Locale(l).getDisplayLanguage());
131 +// System.out.println(lang);
132 +// java.util.Locale.CHINESE.getDisplayLanguage(java.util.Locale.CHINESE);
133 +// for (int i = 0; i < lang.length(); i++) {
134 +// System.out.println(Integer.toHexString(lang.charAt(i)) + " ");
135 +// }
136 +// }
137 +
138 + // private URLClassLoader urlClassLoader;
139 + private int port;
140 + private boolean allowOthers;
141 + private boolean isDaemon;
142 + private final Set<WebThread> running =
143 + Collections.synchronizedSet(new HashSet<WebThread>());
144 + private boolean ssl;
145 + private final HashMap<String, ConnectionInfo> connInfoMap = New.hashMap();
146 +
147 + private long lastTimeoutCheck;
148 + private final HashMap<String, WebSession> sessions = New.hashMap();
149 + private final HashSet<String> languages = New.hashSet();
150 + private String startDateTime;
151 + private ServerSocket serverSocket;
152 + private String url;
153 + private ShutdownHandler shutdownHandler;
154 + private Thread listenerThread;
155 + private boolean ifExists;
156 + private boolean trace;
157 + private TranslateThread translateThread;
158 + private boolean allowChunked = true;
159 + private String serverPropertiesDir = Constants.SERVER_PROPERTIES_DIR;
160 + // null means the history is not allowed to be stored
161 + private String commandHistoryString;
162 +
163 + /**
164 + * Read the given file from the file system or from the resources.
165 + *
166 + * @param file the file name
167 + * @return the data
168 + */
169 + byte[] getFile(String file) throws IOException {
170 + trace("getFile <" + file + ">");
171 + byte[] data = Utils.getResource("/org/h2/server/web/res/" + file);
172 + if (data == null) {
173 + trace(" null");
174 + } else {
175 + trace(" size=" + data.length);
176 + }
177 + return data;
178 + }
179 +
180 + /**
181 + * Check if this is a simple name (only contains '.', '-', '_', letters, or
182 + * digits).
183 + *
184 + * @param s the string
185 + * @return true if it's a simple name
186 + */
187 + static boolean isSimpleName(String s) {
188 + for (char c : s.toCharArray()) {
189 + if (c != '.' && c != '_' && c != '-' && !Character.isLetterOrDigit(c)) {
190 + return false;
191 + }
192 + }
193 + return true;
194 + }
195 +
196 + /**
197 + * Remove this web thread from the set of running threads.
198 + *
199 + * @param t the thread to remove
200 + */
201 + synchronized void remove(WebThread t) {
202 + running.remove(t);
203 + }
204 +
205 + private static String generateSessionId() {
206 + byte[] buff = MathUtils.secureRandomBytes(16);
207 + return StringUtils.convertBytesToHex(buff);
208 + }
209 +
210 + /**
211 + * Get the web session object for the given session id.
212 + *
213 + * @param sessionId the session id
214 + * @return the web session or null
215 + */
216 + WebSession getSession(String sessionId) {
217 + long now = System.currentTimeMillis();
218 + if (lastTimeoutCheck + SESSION_TIMEOUT < now) {
219 + for (String id : New.arrayList(sessions.keySet())) {
220 + WebSession session = sessions.get(id);
221 + if (session.lastAccess + SESSION_TIMEOUT < now) {
222 + trace("timeout for " + id);
223 + sessions.remove(id);
224 + }
225 + }
226 + lastTimeoutCheck = now;
227 + }
228 + WebSession session = sessions.get(sessionId);
229 + if (session != null) {
230 + session.lastAccess = System.currentTimeMillis();
231 + }
232 + return session;
233 + }
234 +
235 + /**
236 + * Create a new web session id and object.
237 + *
238 + * @param hostAddr the host address
239 + * @return the web session object
240 + */
241 + WebSession createNewSession(String hostAddr) {
242 + String newId;
243 + do {
244 + newId = generateSessionId();
245 + } while (sessions.get(newId) != null);
246 + WebSession session = new WebSession(this);
247 + session.lastAccess = System.currentTimeMillis();
248 + session.put("sessionId", newId);
249 + session.put("ip", hostAddr);
250 + session.put("language", DEFAULT_LANGUAGE);
251 + session.put("frame-border", "0");
252 + session.put("frameset-border", "4");
253 + sessions.put(newId, session);
254 + // always read the english translation,
255 + // so that untranslated text appears at least in english
256 + readTranslations(session, DEFAULT_LANGUAGE);
257 + return getSession(newId);
258 + }
259 +
260 + String getStartDateTime() {
261 + if (startDateTime == null) {
262 + SimpleDateFormat format = new SimpleDateFormat(
263 + "EEE, d MMM yyyy HH:mm:ss z", new Locale("en", ""));
264 + format.setTimeZone(TimeZone.getTimeZone("GMT"));
265 + startDateTime = format.format(System.currentTimeMillis());
266 + }
267 + return startDateTime;
268 + }
269 +
270 + @Override
271 + public void init(String... args) {
272 + // set the serverPropertiesDir, because it's used in loadProperties()
273 + for (int i = 0; args != null && i < args.length; i++) {
274 + if ("-properties".equals(args[i])) {
275 + serverPropertiesDir = args[++i];
276 + }
277 + }
278 + Properties prop = loadProperties();
279 + port = SortedProperties.getIntProperty(prop,
280 + "webPort", Constants.DEFAULT_HTTP_PORT);
281 + ssl = SortedProperties.getBooleanProperty(prop,
282 + "webSSL", false);
283 + allowOthers = SortedProperties.getBooleanProperty(prop,
284 + "webAllowOthers", false);
285 + commandHistoryString = prop.getProperty(COMMAND_HISTORY);
286 + for (int i = 0; args != null && i < args.length; i++) {
287 + String a = args[i];
288 + if (Tool.isOption(a, "-webPort")) {
289 + port = Integer.decode(args[++i]);
290 + } else if (Tool.isOption(a, "-webSSL")) {
291 + ssl = true;
292 + } else if (Tool.isOption(a, "-webAllowOthers")) {
293 + allowOthers = true;
294 + } else if (Tool.isOption(a, "-webDaemon")) {
295 + isDaemon = true;
296 + } else if (Tool.isOption(a, "-baseDir")) {
297 + String baseDir = args[++i];
298 + SysProperties.setBaseDir(baseDir);
299 + } else if (Tool.isOption(a, "-ifExists")) {
300 + ifExists = true;
301 + } else if (Tool.isOption(a, "-properties")) {
302 + // already set
303 + i++;
304 + } else if (Tool.isOption(a, "-trace")) {
305 + trace = true;
306 + }
307 + }
308 +// if (driverList != null) {
309 +// try {
310 +// String[] drivers =
311 +// StringUtils.arraySplit(driverList, ',', false);
312 +// URL[] urls = new URL[drivers.length];
313 +// for(int i=0; i<drivers.length; i++) {
314 +// urls[i] = new URL(drivers[i]);
315 +// }
316 +// urlClassLoader = URLClassLoader.newInstance(urls);
317 +// } catch (MalformedURLException e) {
318 +// TraceSystem.traceThrowable(e);
319 +// }
320 +// }
321 + for (String[] lang : LANGUAGES) {
322 + languages.add(lang[0]);
323 + }
324 + updateURL();
325 + }
326 +
327 + @Override
328 + public String getURL() {
329 + updateURL();
330 + return url;
331 + }
332 +
333 + private void updateURL() {
334 + try {
335 + url = (ssl ? "https" : "http") + "://" +
336 + NetUtils.getLocalAddress() + ":" + port;
337 + } catch (NoClassDefFoundError e) {
338 + // Google App Engine does not allow java.net.InetAddress
339 + }
340 + }
341 +
342 + @Override
343 + public void start() {
344 + serverSocket = NetUtils.createServerSocket(port, ssl);
345 + port = serverSocket.getLocalPort();
346 + updateURL();
347 + }
348 +
349 + @Override
350 + public void listen() {
351 + this.listenerThread = Thread.currentThread();
352 + try {
353 + while (serverSocket != null) {
354 + Socket s = serverSocket.accept();
355 + WebThread c = new WebThread(s, this);
356 + running.add(c);
357 + c.start();
358 + }
359 + } catch (Exception e) {
360 + trace(e.toString());
361 + }
362 + }
363 +
364 + @Override
365 + public boolean isRunning(boolean traceError) {
366 + if (serverSocket == null) {
367 + return false;
368 + }
369 + try {
370 + Socket s = NetUtils.createLoopbackSocket(port, ssl);
371 + s.close();
372 + return true;
373 + } catch (Exception e) {
374 + if (traceError) {
375 + traceError(e);
376 + }
377 + return false;
378 + }
379 + }
380 +
381 + public boolean isStopped() {
382 + return serverSocket == null;
383 + }
384 +
385 + @Override
386 + public void stop() {
387 + if (serverSocket != null) {
388 + try {
389 + serverSocket.close();
390 + } catch (IOException e) {
391 + traceError(e);
392 + }
393 + serverSocket = null;
394 + }
395 + if (listenerThread != null) {
396 + try {
397 + listenerThread.join(1000);
398 + } catch (InterruptedException e) {
399 + DbException.traceThrowable(e);
400 + }
401 + }
402 + // TODO server: using a boolean 'now' argument? a timeout?
403 + for (WebSession session : New.arrayList(sessions.values())) {
404 + session.close();
405 + }
406 + for (WebThread c : New.arrayList(running)) {
407 + try {
408 + c.stopNow();
409 + c.join(100);
410 + } catch (Exception e) {
411 + traceError(e);
412 + }
413 + }
414 + }
415 +
416 + /**
417 + * Write trace information if trace is enabled.
418 + *
419 + * @param s the message to write
420 + */
421 + void trace(String s) {
422 + if (trace) {
423 + System.out.println(s);
424 + }
425 + }
426 +
427 + /**
428 + * Write the stack trace if trace is enabled.
429 + *
430 + * @param e the exception
431 + */
432 + void traceError(Throwable e) {
433 + if (trace) {
434 + e.printStackTrace();
435 + }
436 + }
437 +
438 + /**
439 + * Check if this language is supported / translated.
440 + *
441 + * @param language the language
442 + * @return true if a translation is available
443 + */
444 + boolean supportsLanguage(String language) {
445 + return languages.contains(language);
446 + }
447 +
448 + /**
449 + * Read the translation for this language and save them in the 'text'
450 + * property of this session.
451 + *
452 + * @param session the session
453 + * @param language the language
454 + */
455 + void readTranslations(WebSession session, String language) {
456 + Properties text = new Properties();
457 + try {
458 + trace("translation: "+language);
459 + byte[] trans = getFile("_text_"+language+".prop");
460 + trace(" "+new String(trans));
461 + text = SortedProperties.fromLines(new String(trans, Constants.UTF8));
462 + // remove starting # (if not translated yet)
463 + for (Entry<Object, Object> entry : text.entrySet()) {
464 + String value = (String) entry.getValue();
465 + if (value.startsWith("#")) {
466 + entry.setValue(value.substring(1));
467 + }
468 + }
469 + } catch (IOException e) {
470 + DbException.traceThrowable(e);
471 + }
472 + session.put("text", new HashMap<Object, Object>(text));
473 + }
474 +
475 + ArrayList<HashMap<String, Object>> getSessions() {
476 + ArrayList<HashMap<String, Object>> list = New.arrayList();
477 + for (WebSession s : sessions.values()) {
478 + list.add(s.getInfo());
479 + }
480 + return list;
481 + }
482 +
483 + @Override
484 + public String getType() {
485 + return "Web Console";
486 + }
487 +
488 + @Override
489 + public String getName() {
490 + return "H2 Console Server";
491 + }
492 +
493 + void setAllowOthers(boolean b) {
494 + allowOthers = b;
495 + }
496 +
497 + @Override
498 + public boolean getAllowOthers() {
499 + return allowOthers;
500 + }
501 +
502 + void setSSL(boolean b) {
503 + ssl = b;
504 + }
505 +
506 + void setPort(int port) {
507 + this.port = port;
508 + }
509 +
510 + boolean getSSL() {
511 + return ssl;
512 + }
513 +
514 + @Override
515 + public int getPort() {
516 + return port;
517 + }
518 +
519 + public boolean isCommandHistoryAllowed() {
520 + return commandHistoryString != null;
521 + }
522 +
523 + public void setCommandHistoryAllowed(boolean allowed) {
524 + if (allowed) {
525 + if (commandHistoryString == null) {
526 + commandHistoryString = "";
527 + }
528 + } else {
529 + commandHistoryString = null;
530 + }
531 + }
532 +
533 + public ArrayList<String> getCommandHistoryList() {
534 + ArrayList<String> result = New.arrayList();
535 + if (commandHistoryString == null) {
536 + return result;
537 + }
538 +
539 + // Split the commandHistoryString on non-escaped semicolons
540 + // and unescape it.
541 + StringBuilder sb = new StringBuilder();
542 + for (int end = 0;; end++) {
543 + if (end == commandHistoryString.length() ||
544 + commandHistoryString.charAt(end) == ';') {
545 + if (sb.length() > 0) {
546 + result.add(sb.toString());
547 + sb.delete(0, sb.length());
548 + }
549 + if (end == commandHistoryString.length()) {
550 + break;
551 + }
552 + } else if (commandHistoryString.charAt(end) == '\\' &&
553 + end < commandHistoryString.length() - 1) {
554 + sb.append(commandHistoryString.charAt(++end));
555 + } else {
556 + sb.append(commandHistoryString.charAt(end));
557 + }
558 + }
559 + return result;
560 + }
561 +
562 + /**
563 + * Save the command history to the properties file.
564 + *
565 + * @param commandHistory the history
566 + */
567 + public void saveCommandHistoryList(ArrayList<String> commandHistory) {
568 + StringBuilder sb = new StringBuilder();
569 + for (String s : commandHistory) {
570 + if (sb.length() > 0) {
571 + sb.append(';');
572 + }
573 + sb.append(s.replace("\\", "\\\\").replace(";", "\\;"));
574 + }
575 + commandHistoryString = sb.toString();
576 + saveProperties(null);
577 + }
578 +
579 + /**
580 + * Get the connection information for this setting.
581 + *
582 + * @param name the setting name
583 + * @return the connection information
584 + */
585 + ConnectionInfo getSetting(String name) {
586 + return connInfoMap.get(name);
587 + }
588 +
589 + /**
590 + * Update a connection information setting.
591 + *
592 + * @param info the connection information
593 + */
594 + void updateSetting(ConnectionInfo info) {
595 + connInfoMap.put(info.name, info);
596 + info.lastAccess = ticker++;
597 + }
598 +
599 + /**
600 + * Remove a connection information setting from the list
601 + *
602 + * @param name the setting to remove
603 + */
604 + void removeSetting(String name) {
605 + connInfoMap.remove(name);
606 + }
607 +
608 + private Properties loadProperties() {
609 + try {
610 + if ("null".equals(serverPropertiesDir)) {
611 + return new Properties();
612 + }
613 + return SortedProperties.loadProperties(
614 + serverPropertiesDir + "/" + Constants.SERVER_PROPERTIES_NAME);
615 + } catch (Exception e) {
616 + DbException.traceThrowable(e);
617 + return new Properties();
618 + }
619 + }
620 +
621 + /**
622 + * Get the list of connection information setting names.
623 + *
624 + * @return the connection info names
625 + */
626 + String[] getSettingNames() {
627 + ArrayList<ConnectionInfo> list = getSettings();
628 + String[] names = new String[list.size()];
629 + for (int i = 0; i < list.size(); i++) {
630 + names[i] = list.get(i).name;
631 + }
632 + return names;
633 + }
634 +
635 + /**
636 + * Get the list of connection info objects.
637 + *
638 + * @return the list
639 + */
640 + synchronized ArrayList<ConnectionInfo> getSettings() {
641 + ArrayList<ConnectionInfo> settings = New.arrayList();
642 + if (connInfoMap.size() == 0) {
643 + Properties prop = loadProperties();
644 + if (prop.size() == 0) {
645 + for (String gen : GENERIC) {
646 + ConnectionInfo info = new ConnectionInfo(gen);
647 + settings.add(info);
648 + updateSetting(info);
649 + }
650 + } else {
651 + for (int i = 0;; i++) {
652 + String data = prop.getProperty(String.valueOf(i));
653 + if (data == null) {
654 + break;
655 + }
656 + ConnectionInfo info = new ConnectionInfo(data);
657 + settings.add(info);
658 + updateSetting(info);
659 + }
660 + }
661 + } else {
662 + settings.addAll(connInfoMap.values());
663 + }
664 + Collections.sort(settings);
665 + return settings;
666 + }
667 +
668 + /**
669 + * Save the settings to the properties file.
670 + *
671 + * @param prop null or the properties webPort, webAllowOthers, and webSSL
672 + */
673 + synchronized void saveProperties(Properties prop) {
674 + try {
675 + if (prop == null) {
676 + Properties old = loadProperties();
677 + prop = new SortedProperties();
678 + prop.setProperty("webPort",
679 + "" + SortedProperties.getIntProperty(old,
680 + "webPort", port));
681 + prop.setProperty("webAllowOthers",
682 + "" + SortedProperties.getBooleanProperty(old,
683 + "webAllowOthers", allowOthers));
684 + prop.setProperty("webSSL",
685 + "" + SortedProperties.getBooleanProperty(old,
686 + "webSSL", ssl));
687 + if (commandHistoryString != null) {
688 + prop.setProperty(COMMAND_HISTORY, commandHistoryString);
689 + }
690 + }
691 + ArrayList<ConnectionInfo> settings = getSettings();
692 + int len = settings.size();
693 + for (int i = 0; i < len; i++) {
694 + ConnectionInfo info = settings.get(i);
695 + if (info != null) {
696 + prop.setProperty(String.valueOf(len - i - 1), info.getString());
697 + }
698 + }
699 + if (!"null".equals(serverPropertiesDir)) {
700 + OutputStream out = FileUtils.newOutputStream(
701 + serverPropertiesDir + "/" + Constants.SERVER_PROPERTIES_NAME, false);
702 + prop.store(out, "H2 Server Properties");
703 + out.close();
704 + }
705 + } catch (Exception e) {
706 + DbException.traceThrowable(e);
707 + }
708 + }
709 +
710 + /**
711 + * Open a database connection.
712 + *
713 + * @param driver the driver class name
714 + * @param databaseUrl the database URL
715 + * @param user the user name
716 + * @param password the password
717 + * @return the database connection
718 + */
719 + Connection getConnection(String driver, String databaseUrl, String user,
720 + String password) throws SQLException {
721 + driver = driver.trim();
722 + databaseUrl = databaseUrl.trim();
723 + org.h2.Driver.load();
724 + Properties p = new Properties();
725 + p.setProperty("user", user.trim());
726 + // do not trim the password, otherwise an
727 + // encrypted H2 database with empty user password doesn't work
728 + p.setProperty("password", password);
729 + if (databaseUrl.startsWith("jdbc:h2:")) {
730 + if (ifExists) {
731 + databaseUrl += ";IFEXISTS=TRUE";
732 + }
733 + // PostgreSQL would throw a NullPointerException
734 + // if it is loaded before the H2 driver
735 + // because it can't deal with non-String objects in the connection
736 + // Properties
737 + return org.h2.Driver.load().connect(databaseUrl, p);
738 + }
739 +// try {
740 +// Driver dr = (Driver) urlClassLoader.
741 +// loadClass(driver).newInstance();
742 +// return dr.connect(url, p);
743 +// } catch(ClassNotFoundException e2) {
744 +// throw e2;
745 +// }
746 + return JdbcUtils.getConnection(driver, databaseUrl, p);
747 + }
748 +
749 + /**
750 + * Shut down the web server.
751 + */
752 + void shutdown() {
753 + if (shutdownHandler != null) {
754 + shutdownHandler.shutdown();
755 + }
756 + }
757 +
758 + public void setShutdownHandler(ShutdownHandler shutdownHandler) {
759 + this.shutdownHandler = shutdownHandler;
760 + }
761 +
762 + /**
763 + * Create a session with a given connection.
764 + *
765 + * @param conn the connection
766 + * @return the URL of the web site to access this connection
767 + */
768 + public String addSession(Connection conn) throws SQLException {
769 + WebSession session = createNewSession("local");
770 + session.setShutdownServerOnDisconnect();
771 + session.setConnection(conn);
772 + session.put("url", conn.getMetaData().getURL());
773 + String s = (String) session.get("sessionId");
774 + return url + "/frame.jsp?jsessionid=" + s;
775 + }
776 +
777 + /**
778 + * The translate thread reads and writes the file translation.properties
779 + * once a second.
780 + */
781 + private class TranslateThread extends Thread {
782 +
783 + private final File file = new File("translation.properties");
784 + private final Map<Object, Object> translation;
785 + private volatile boolean stopNow;
786 +
787 + TranslateThread(Map<Object, Object> translation) {
788 + this.translation = translation;
789 + }
790 +
791 + public String getFileName() {
792 + return file.getAbsolutePath();
793 + }
794 +
795 + public void stopNow() {
796 + this.stopNow = true;
797 + try {
798 + join();
799 + } catch (InterruptedException e) {
800 + // ignore
801 + }
802 + }
803 +
804 + @Override
805 + public void run() {
806 + while (!stopNow) {
807 + try {
808 + SortedProperties sp = new SortedProperties();
809 + if (file.exists()) {
810 + InputStream in = FileUtils.newInputStream(file.getName());
811 + sp.load(in);
812 + translation.putAll(sp);
813 + } else {
814 + OutputStream out = FileUtils.newOutputStream(file.getName(), false);
815 + sp.putAll(translation);
816 + sp.store(out, "Translation");
817 + }
818 + Thread.sleep(1000);
819 + } catch (Exception e) {
820 + traceError(e);
821 + }
822 + }
823 + }
824 +
825 + }
826 +
827 + /**
828 + * Start the translation thread that reads the file once a second.
829 + *
830 + * @param translation the translation map
831 + * @return the name of the file to translate
832 + */
833 + String startTranslate(Map<Object, Object> translation) {
834 + if (translateThread != null) {
835 + translateThread.stopNow();
836 + }
837 + translateThread = new TranslateThread(translation);
838 + translateThread.setDaemon(true);
839 + translateThread.start();
840 + return translateThread.getFileName();
841 + }
842 +
843 + @Override
844 + public boolean isDaemon() {
845 + return isDaemon;
846 + }
847 +
848 + void setAllowChunked(boolean allowChunked) {
849 + this.allowChunked = allowChunked;
850 + }
851 +
852 + boolean getAllowChunked() {
853 + return allowChunked;
854 + }
855 +
856 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.legrog.util;
2 +// Code copied from org.h2.server.web.WebSession
3 +/*
4 + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
5 + * and the EPL 1.0 (http://h2database.com/html/license.html).
6 + * Initial Developer: H2 Group
7 + */
8 +///package org.h2.server.web;
9 +
10 + import java.sql.Connection;
11 + import java.sql.DatabaseMetaData;
12 + import java.sql.ResultSet;
13 + import java.sql.SQLException;
14 + import java.sql.Statement;
15 + import java.sql.Timestamp;
16 + import java.util.ArrayList;
17 + import java.util.HashMap;
18 + import java.util.Locale;
19 +
20 + import org.h2.bnf.Bnf;
21 + import org.h2.bnf.context.DbContents;
22 + import org.h2.bnf.context.DbContextRule;
23 + import org.h2.message.DbException;
24 + import org.h2.util.New;
25 +import org.h2.server.web.*;
26 +
27 +/**
28 + * The web session keeps all data of a user session.
29 + * This class is used by the H2 Console.
30 + */
31 +class WebSession {
32 +
33 + private static final int MAX_HISTORY = 1000;
34 +
35 + /**
36 + * The last time this client sent a request.
37 + */
38 + long lastAccess;
39 +
40 + /**
41 + * The session attribute map.
42 + */
43 + final HashMap<String, Object> map = New.hashMap();
44 +
45 + /**
46 + * The current locale.
47 + */
48 + Locale locale;
49 +
50 + /**
51 + * The currently executing statement.
52 + */
53 + Statement executingStatement;
54 +
55 + /**
56 + * The current updatable result set.
57 + */
58 + ResultSet result;
59 +
60 + private final WebServer server;
61 +
62 + private final ArrayList<String> commandHistory;
63 +
64 + private Connection conn;
65 + private DatabaseMetaData meta;
66 + private DbContents contents = new DbContents();
67 + private Bnf bnf;
68 + private boolean shutdownServerOnDisconnect;
69 +
70 + WebSession(WebServer server) {
71 + this.server = server;
72 + // This must be stored in the session rather than in the server.
73 + // Otherwise, one client could allow
74 + // saving history for others (insecure).
75 + this.commandHistory = server.getCommandHistoryList();
76 + }
77 +
78 + /**
79 + * Put an attribute value in the map.
80 + *
81 + * @param key the key
82 + * @param value the new value
83 + */
84 + void put(String key, Object value) {
85 + map.put(key, value);
86 + }
87 +
88 + /**
89 + * Get the value for the given key.
90 + *
91 + * @param key the key
92 + * @return the value
93 + */
94 + Object get(String key) {
95 + if ("sessions".equals(key)) {
96 + return server.getSessions();
97 + }
98 + return map.get(key);
99 + }
100 +
101 + /**
102 + * Remove a session attribute from the map.
103 + *
104 + * @param key the key
105 + */
106 + void remove(String key) {
107 + map.remove(key);
108 + }
109 +
110 + /**
111 + * Get the BNF object.
112 + *
113 + * @return the BNF object
114 + */
115 + Bnf getBnf() {
116 + return bnf;
117 + }
118 +
119 + /**
120 + * Load the SQL grammar BNF.
121 + */
122 + void loadBnf() {
123 + try {
124 + Bnf newBnf = Bnf.getInstance(null);
125 + DbContextRule columnRule =
126 + new DbContextRule(contents, DbContextRule.COLUMN);
127 + DbContextRule newAliasRule =
128 + new DbContextRule(contents, DbContextRule.NEW_TABLE_ALIAS);
129 + DbContextRule aliasRule =
130 + new DbContextRule(contents, DbContextRule.TABLE_ALIAS);
131 + DbContextRule tableRule =
132 + new DbContextRule(contents, DbContextRule.TABLE);
133 + DbContextRule schemaRule =
134 + new DbContextRule(contents, DbContextRule.SCHEMA);
135 + DbContextRule columnAliasRule =
136 + new DbContextRule(contents, DbContextRule.COLUMN_ALIAS);
137 + DbContextRule procedure =
138 + new DbContextRule(contents, DbContextRule.PROCEDURE);
139 + newBnf.updateTopic("procedure", procedure);
140 + newBnf.updateTopic("column_name", columnRule);
141 + newBnf.updateTopic("new_table_alias", newAliasRule);
142 + newBnf.updateTopic("table_alias", aliasRule);
143 + newBnf.updateTopic("column_alias", columnAliasRule);
144 + newBnf.updateTopic("table_name", tableRule);
145 + newBnf.updateTopic("schema_name", schemaRule);
146 + newBnf.linkStatements();
147 + bnf = newBnf;
148 + } catch (Exception e) {
149 + // ok we don't have the bnf
150 + server.traceError(e);
151 + }
152 + }
153 +
154 + /**
155 + * Get the SQL statement from history.
156 + *
157 + * @param id the history id
158 + * @return the SQL statement
159 + */
160 + String getCommand(int id) {
161 + return commandHistory.get(id);
162 + }
163 +
164 + /**
165 + * Add a SQL statement to the history.
166 + *
167 + * @param sql the SQL statement
168 + */
169 + void addCommand(String sql) {
170 + if (sql == null) {
171 + return;
172 + }
173 + sql = sql.trim();
174 + if (sql.length() == 0) {
175 + return;
176 + }
177 + if (commandHistory.size() > MAX_HISTORY) {
178 + commandHistory.remove(0);
179 + }
180 + int idx = commandHistory.indexOf(sql);
181 + if (idx >= 0) {
182 + commandHistory.remove(idx);
183 + }
184 + commandHistory.add(sql);
185 + if (server.isCommandHistoryAllowed()) {
186 + server.saveCommandHistoryList(commandHistory);
187 + }
188 + }
189 +
190 + /**
191 + * Get the list of SQL statements in the history.
192 + *
193 + * @return the commands
194 + */
195 + ArrayList<String> getCommandHistory() {
196 + return commandHistory;
197 + }
198 +
199 + /**
200 + * Update session meta data information and get the information in a map.
201 + *
202 + * @return a map containing the session meta data
203 + */
204 + HashMap<String, Object> getInfo() {
205 + HashMap<String, Object> m = New.hashMap();
206 + m.putAll(map);
207 + m.put("lastAccess", new Timestamp(lastAccess).toString());
208 + try {
209 + m.put("url", conn == null ?
210 + "${text.admin.notConnected}" : conn.getMetaData().getURL());
211 + m.put("user", conn == null ?
212 + "-" : conn.getMetaData().getUserName());
213 + m.put("lastQuery", commandHistory.size() == 0 ?
214 + "" : commandHistory.get(0));
215 + m.put("executing", executingStatement == null ?
216 + "${text.admin.no}" : "${text.admin.yes}");
217 + } catch (SQLException e) {
218 + DbException.traceThrowable(e);
219 + }
220 + return m;
221 + }
222 +
223 + void setConnection(Connection conn) throws SQLException {
224 + this.conn = conn;
225 + if (conn == null) {
226 + meta = null;
227 + } else {
228 + meta = conn.getMetaData();
229 + }
230 + contents = new DbContents();
231 + }
232 +
233 + DatabaseMetaData getMetaData() {
234 + return meta;
235 + }
236 +
237 + Connection getConnection() {
238 + return conn;
239 + }
240 +
241 + DbContents getContents() {
242 + return contents;
243 + }
244 +
245 + /**
246 + * Shutdown the server when disconnecting.
247 + */
248 + void setShutdownServerOnDisconnect() {
249 + this.shutdownServerOnDisconnect = true;
250 + }
251 +
252 + boolean getShutdownServerOnDisconnect() {
253 + return shutdownServerOnDisconnect;
254 + }
255 +
256 + /**
257 + * Close the connection and stop the statement if one is currently
258 + * executing.
259 + */
260 + void close() {
261 + if (executingStatement != null) {
262 + try {
263 + executingStatement.cancel();
264 + } catch (Exception e) {
265 + // ignore
266 + }
267 + }
268 + if (conn != null) {
269 + try {
270 + conn.close();
271 + } catch (Exception e) {
272 + // ignore
273 + }
274 + }
275 +
276 + }
277 +
278 +}
...\ No newline at end of file ...\ No newline at end of file
1 +package org.legrog.util;
2 +// Code copied from org.h2.server.web.WebThread
3 +/*
4 + * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
5 + * and the EPL 1.0 (http://h2database.com/html/license.html).
6 + * Initial Developer: H2 Group
7 + */
8 +//package org.h2.server.web;
9 +
10 + import java.io.BufferedInputStream;
11 + import java.io.BufferedOutputStream;
12 + import java.io.IOException;
13 + import java.io.InputStream;
14 + import java.io.OutputStream;
15 + import java.net.Socket;
16 + import java.net.UnknownHostException;
17 + import java.util.Iterator;
18 + import java.util.Locale;
19 + import java.util.Properties;
20 + import java.util.StringTokenizer;
21 + import org.h2.engine.Constants;
22 + import org.h2.engine.SysProperties;
23 + import org.h2.message.DbException;
24 + import org.h2.mvstore.DataUtils;
25 + import org.h2.util.IOUtils;
26 + import org.h2.util.NetUtils;
27 + import org.h2.util.StringUtils;
28 +//import org.h2.server.web.*;
29 +
30 +/**
31 + * For each connection to a session, an object of this class is created.
32 + * This class is used by the H2 Console.
33 + */
34 +class WebThread extends WebApp implements Runnable {
35 +
36 + protected OutputStream output;
37 + protected final Socket socket;
38 + private final Thread thread;
39 + private InputStream input;
40 + private String ifModifiedSince;
41 +
42 + WebThread(Socket socket, WebServer server) {
43 + super(server);
44 + this.socket = socket;
45 + thread = new Thread(this, "H2 Console thread");
46 + }
47 +
48 + /**
49 + * Start the thread.
50 + */
51 + void start() {
52 + thread.start();
53 + }
54 +
55 + /**
56 + * Wait until the thread is stopped.
57 + *
58 + * @param millis the maximum number of milliseconds to wait
59 + */
60 + void join(int millis) throws InterruptedException {
61 + thread.join(millis);
62 + }
63 +
64 + /**
65 + * Close the connection now.
66 + */
67 + void stopNow() {
68 + this.stop = true;
69 + try {
70 + socket.close();
71 + } catch (IOException e) {
72 + // ignore
73 + }
74 + }
75 +
76 + private String getAllowedFile(String requestedFile) {
77 + if (!allow()) {
78 + return "notAllowed.jsp";
79 + }
80 + if (requestedFile.length() == 0) {
81 + return "index.do";
82 + }
83 + return requestedFile;
84 + }
85 +
86 + @Override
87 + public void run() {
88 + try {
89 + input = new BufferedInputStream(socket.getInputStream());
90 + output = new BufferedOutputStream(socket.getOutputStream());
91 + while (!stop) {
92 + if (!process()) {
93 + break;
94 + }
95 + }
96 + } catch (Exception e) {
97 + DbException.traceThrowable(e);
98 + }
99 + IOUtils.closeSilently(output);
100 + IOUtils.closeSilently(input);
101 + try {
102 + socket.close();
103 + } catch (IOException e) {
104 + // ignore
105 + } finally {
106 + server.remove(this);
107 + }
108 + }
109 +
110 + @SuppressWarnings("unchecked")
111 + private boolean process() throws IOException {
112 + boolean keepAlive = false;
113 + String head = readHeaderLine();
114 + if (head.startsWith("GET ") || head.startsWith("POST ")) {
115 + int begin = head.indexOf('/'), end = head.lastIndexOf(' ');
116 + String file;
117 + if (begin < 0 || end < begin) {
118 + file = "";
119 + } else {
120 + file = head.substring(begin + 1, end).trim();
121 + }
122 + trace(head + ": " + file);
123 + file = getAllowedFile(file);
124 + attributes = new Properties();
125 + int paramIndex = file.indexOf("?");
126 + session = null;
127 + if (paramIndex >= 0) {
128 + String attrib = file.substring(paramIndex + 1);
129 + parseAttributes(attrib);
130 + String sessionId = attributes.getProperty("jsessionid");
131 + file = file.substring(0, paramIndex);
132 + session = server.getSession(sessionId);
133 + }
134 + keepAlive = parseHeader();
135 + String hostAddr = socket.getInetAddress().getHostAddress();
136 + file = processRequest(file, hostAddr);
137 + if (file.length() == 0) {
138 + // asynchronous request
139 + return true;
140 + }
141 + String message;
142 + byte[] bytes;
143 + if (cache && ifModifiedSince != null &&
144 + ifModifiedSince.equals(server.getStartDateTime())) {
145 + bytes = null;
146 + message = "HTTP/1.1 304 Not Modified\r\n";
147 + } else {
148 + bytes = server.getFile(file);
149 + if (bytes == null) {
150 + message = "HTTP/1.1 404 Not Found\r\n";
151 + bytes = ("File not found: " + file).getBytes(Constants.UTF8);
152 + message += "Content-Length: " + bytes.length + "\r\n";
153 + } else {
154 + if (session != null && file.endsWith(".jsp")) {
155 + String page = new String(bytes, Constants.UTF8);
156 + if (SysProperties.CONSOLE_STREAM) {
157 + Iterator<String> it = (Iterator<String>) session.map.remove("chunks");
158 + if (it != null) {
159 + message = "HTTP/1.1 200 OK\r\n";
160 + message += "Content-Type: " + mimeType + "\r\n";
161 + message += "Cache-Control: no-cache\r\n";
162 + message += "Transfer-Encoding: chunked\r\n";
163 + message += "\r\n";
164 + trace(message);
165 + output.write(message.getBytes());
166 + while (it.hasNext()) {
167 + String s = it.next();
168 + s = PageParser.parse(s, session.map);
169 + bytes = s.getBytes(Constants.UTF8);
170 + if (bytes.length == 0) {
171 + continue;
172 + }
173 + output.write(Integer.toHexString(bytes.length).getBytes());
174 + output.write("\r\n".getBytes());
175 + output.write(bytes);
176 + output.write("\r\n".getBytes());
177 + output.flush();
178 + }
179 + output.write("0\r\n\r\n".getBytes());
180 + output.flush();
181 + return keepAlive;
182 + }
183 + }
184 + page = PageParser.parse(page, session.map);
185 + bytes = page.getBytes(Constants.UTF8);
186 + }
187 + message = "HTTP/1.1 200 OK\r\n";
188 + message += "Content-Type: " + mimeType + "\r\n";
189 + if (!cache) {
190 + message += "Cache-Control: no-cache\r\n";
191 + } else {
192 + message += "Cache-Control: max-age=10\r\n";
193 + message += "Last-Modified: " + server.getStartDateTime() + "\r\n";
194 + }
195 + message += "Content-Length: " + bytes.length + "\r\n";
196 + }
197 + }
198 + message += "\r\n";
199 + trace(message);
200 + output.write(message.getBytes());
201 + if (bytes != null) {
202 + output.write(bytes);
203 + }
204 + output.flush();
205 + }
206 + return keepAlive;
207 + }
208 +
209 + private String readHeaderLine() throws IOException {
210 + StringBuilder buff = new StringBuilder();
211 + while (true) {
212 + int c = input.read();
213 + if (c == -1) {
214 + throw new IOException("Unexpected EOF");
215 + } else if (c == '\r') {
216 + if (input.read() == '\n') {
217 + return buff.length() > 0 ? buff.toString() : null;
218 + }
219 + } else if (c == '\n') {
220 + return buff.length() > 0 ? buff.toString() : null;
221 + } else {
222 + buff.append((char) c);
223 + }
224 + }
225 + }
226 +
227 + private void parseAttributes(String s) {
228 + trace("data=" + s);
229 + while (s != null) {
230 + int idx = s.indexOf('=');
231 + if (idx >= 0) {
232 + String property = s.substring(0, idx);
233 + s = s.substring(idx + 1);
234 + idx = s.indexOf('&');
235 + String value;
236 + if (idx >= 0) {
237 + value = s.substring(0, idx);
238 + s = s.substring(idx + 1);
239 + } else {
240 + value = s;
241 + }
242 + String attr = StringUtils.urlDecode(value);
243 + attributes.put(property, attr);
244 + } else {
245 + break;
246 + }
247 + }
248 + trace(attributes.toString());
249 + }
250 +
251 + private boolean parseHeader() throws IOException {
252 + boolean keepAlive = false;
253 + trace("parseHeader");
254 + int len = 0;
255 + ifModifiedSince = null;
256 + boolean multipart = false;
257 + while (true) {
258 + String line = readHeaderLine();
259 + if (line == null) {
260 + break;
261 + }
262 + trace(" " + line);
263 + String lower = StringUtils.toLowerEnglish(line);
264 + if (lower.startsWith("if-modified-since")) {
265 + ifModifiedSince = getHeaderLineValue(line);
266 + } else if (lower.startsWith("connection")) {
267 + String conn = getHeaderLineValue(line);
268 + if ("keep-alive".equals(conn)) {
269 + keepAlive = true;
270 + }
271 + } else if (lower.startsWith("content-type")) {
272 + String type = getHeaderLineValue(line);
273 + if (type.startsWith("multipart/form-data")) {
274 + multipart = true;
275 + }
276 + } else if (lower.startsWith("content-length")) {
277 + len = Integer.parseInt(getHeaderLineValue(line));
278 + trace("len=" + len);
279 + } else if (lower.startsWith("user-agent")) {
280 + boolean isWebKit = lower.contains("webkit/");
281 + if (isWebKit && session != null) {
282 + // workaround for what seems to be a WebKit bug:
283 + // http://code.google.com/p/chromium/issues/detail?id=6402
284 + session.put("frame-border", "1");
285 + session.put("frameset-border", "2");
286 + }
287 + } else if (lower.startsWith("accept-language")) {
288 + Locale locale = session == null ? null : session.locale;
289 + if (locale == null) {
290 + String languages = getHeaderLineValue(line);
291 + StringTokenizer tokenizer = new StringTokenizer(languages, ",;");
292 + while (tokenizer.hasMoreTokens()) {
293 + String token = tokenizer.nextToken();
294 + if (!token.startsWith("q=")) {
295 + if (server.supportsLanguage(token)) {
296 + int dash = token.indexOf('-');
297 + if (dash >= 0) {
298 + String language = token.substring(0, dash);
299 + String country = token.substring(dash + 1);
300 + locale = new Locale(language, country);
301 + } else {
302 + locale = new Locale(token, "");
303 + }
304 + headerLanguage = locale.getLanguage();
305 + if (session != null) {
306 + session.locale = locale;
307 + session.put("language", headerLanguage);
308 + server.readTranslations(session, headerLanguage);
309 + }
310 + break;
311 + }
312 + }
313 + }
314 + }
315 + } else if (line.trim().length() == 0) {
316 + break;
317 + }
318 + }
319 + if (multipart) {
320 + // not supported
321 + } else if (session != null && len > 0) {
322 + byte[] bytes = DataUtils.newBytes(len);
323 + for (int pos = 0; pos < len;) {
324 + pos += input.read(bytes, pos, len - pos);
325 + }
326 + String s = new String(bytes);
327 + parseAttributes(s);
328 + }
329 + return keepAlive;
330 + }
331 +
332 + private static String getHeaderLineValue(String line) {
333 + return line.substring(line.indexOf(':') + 1).trim();
334 + }
335 +
336 + @Override
337 + protected String adminShutdown() {
338 + stopNow();
339 + return super.adminShutdown();
340 + }
341 +
342 + private boolean allow() {
343 + if (server.getAllowOthers()) {
344 + return true;
345 + }
346 + try {
347 + return NetUtils.isLocalAddress(socket);
348 + } catch (UnknownHostException e) {
349 + server.traceError(e);
350 + return false;
351 + }
352 + }
353 +
354 + private void trace(String s) {
355 + server.trace(s);
356 + }
357 +}
...\ No newline at end of file ...\ No newline at end of file