comparison src/main/java/org/monetdb/mcl/net/Target.java @ 834:5aa19bbed0d6 monetdbs

Comments and formatting
author Joeri van Ruth <joeri.van.ruth@monetdbsolutions.com>
date Wed, 13 Dec 2023 15:39:47 +0100 (17 months ago)
parents 425592a53fcd
children b80758ef25db
comparison
equal deleted inserted replaced
813:a71afa48f269 834:5aa19bbed0d6
3 import java.net.URISyntaxException; 3 import java.net.URISyntaxException;
4 import java.util.Properties; 4 import java.util.Properties;
5 import java.util.regex.Pattern; 5 import java.util.regex.Pattern;
6 6
7 public class Target { 7 public class Target {
8 private boolean tls = false; 8 protected static final Target defaults = new Target();
9 private String host = ""; 9 private static final Pattern namePattern = Pattern.compile("^[a-zzA-Z_][-a-zA-Z0-9_.]*$");
10 private int port = -1; 10 private static final Pattern hashPattern = Pattern.compile("^sha256:[0-9a-fA-F:]*$");
11 private String database = ""; 11 private boolean tls = false;
12 private String tableschema = ""; 12 private String host = "";
13 private String table = ""; 13 private int port = -1;
14 private String sock = ""; 14 private String database = "";
15 private String sockdir = "/tmp"; 15 private String tableschema = "";
16 private String cert = ""; 16 private String table = "";
17 private String certhash = ""; 17 private String sock = "";
18 private String clientkey = ""; 18 private String sockdir = "/tmp";
19 private String clientcert = ""; 19 private String cert = "";
20 private String user = ""; 20 private String certhash = "";
21 private String password = ""; 21 private String clientkey = "";
22 private String language = "sql"; 22 private String clientcert = "";
23 private boolean autocommit = true; 23 private String user = "";
24 private String schema = ""; 24 private String password = "";
25 private int timezone; 25 private String language = "sql";
26 private String binary = "on"; 26 private boolean autocommit = true;
27 private int replySize = 250; 27 private String schema = "";
28 private String hash = ""; 28 private int timezone;
29 private boolean debug = false; 29 private String binary = "on";
30 private String logfile = ""; 30 private int replySize = 250;
31 private int soTimeout = 0; 31 private String hash = "";
32 private boolean treatClobAsVarchar = true; 32 private boolean debug = false;
33 private boolean treatBlobAsBinary = true; 33 private String logfile = "";
34 34 private int soTimeout = 0;
35 private boolean userWasSet = false; 35 private boolean treatClobAsVarchar = true;
36 private boolean passwordWasSet = false; 36 private boolean treatBlobAsBinary = true;
37 protected static final Target defaults = new Target(); 37 private boolean userWasSet = false;
38 private Validated validated = null; 38 private boolean passwordWasSet = false;
39 39 private Validated validated = null;
40 private static Pattern namePattern = Pattern.compile("^[a-zzA-Z_][-a-zA-Z0-9_.]*$"); 40
41 private static Pattern hashPattern = Pattern.compile("^sha256:[0-9a-fA-F:]*$"); 41 public Target() {
42 42 this.timezone = (int) Parameter.TIMEZONE.getDefault();
43 public Target() { 43 }
44 this.timezone = (int)Parameter.TIMEZONE.getDefault(); 44
45 } 45 public Target(String url, Properties props) throws URISyntaxException, ValidationError {
46 46 this();
47 public Target(String url, Properties props) throws URISyntaxException, ValidationError { 47 setProperties(props);
48 this(); 48 parseUrl(url);
49 setProperties(props); 49 }
50 parseUrl(url); 50
51 } 51 public static String packHost(String host) {
52 52 switch (host) {
53 public void barrier() { 53 case "localhost":
54 if (userWasSet && !passwordWasSet) 54 return "localhost.";
55 password = ""; 55 case "":
56 userWasSet = false; 56 return "localhost";
57 passwordWasSet = false; 57 default:
58 } 58 return host;
59 59 }
60 public static String packHost(String host) { 60 }
61 switch (host) { 61
62 case "localhost": 62 public static String unpackHost(String host) {
63 return "localhost."; 63 switch (host) {
64 case "": 64 case "localhost.":
65 return "localhost"; 65 return "localhost";
66 default: 66 case "localhost":
67 return host; 67 return "";
68 } 68 default:
69 } 69 return host;
70 70 }
71 public static String unpackHost(String host) { 71 }
72 switch (host) { 72
73 case "localhost.": 73 public void barrier() {
74 return "localhost"; 74 if (userWasSet && !passwordWasSet)
75 case "localhost": 75 password = "";
76 return ""; 76 userWasSet = false;
77 default: 77 passwordWasSet = false;
78 return host; 78 }
79 } 79
80 } 80 public void setString(String key, String value) throws ValidationError {
81 81 Parameter parm = Parameter.forName(key);
82 public void setString(String key, String value) throws ValidationError { 82 if (parm != null)
83 Parameter parm = Parameter.forName(key); 83 setString(parm, value);
84 if (parm != null) 84 else if (!Parameter.isIgnored(key))
85 setString(parm, value); 85 throw new ValidationError(key, "unknown parameter");
86 else if (!Parameter.isIgnored(key)) 86 }
87 throw new ValidationError(key, "unknown parameter"); 87
88 } 88 public void setString(Parameter parm, String value) throws ValidationError {
89 89 if (value == null)
90 public void setString(Parameter parm, String value) throws ValidationError { 90 throw new NullPointerException("'value' must not be null");
91 if (value == null) 91 assign(parm, parm.type.parse(parm.name, value));
92 throw new NullPointerException("'value' must not be null"); 92 }
93 assign(parm, parm.type.parse(parm.name, value)); 93
94 } 94 public void clear(Parameter parm) {
95 95 assign(parm, parm.getDefault());
96 public void clear(Parameter parm) { 96 }
97 assign(parm, parm.getDefault()); 97
98 } 98 public void parseUrl(String url) throws URISyntaxException, ValidationError {
99 99 if (url == null)
100 public void setProperties(Properties props) throws ValidationError { 100 return;
101 if (props != null) { 101 if (url.startsWith("jdbc:"))
102 for (String key : props.stringPropertyNames()) { 102 url = url.substring(5);
103 String value = props.getProperty(key); 103 if (url.equals("monetdb:")) {
104 if (key.equals(Parameter.HOST.name)) 104 return;
105 value = Target.unpackHost(value); 105 }
106 setString(key, value); 106 MonetUrlParser.parse(this, url);
107 } 107 }
108 } 108
109 } 109 private void assign(Parameter parm, Object value) {
110 110 switch (parm) {
111 public void parseUrl(String url) throws URISyntaxException, ValidationError { 111 case TLS:
112 if (url == null) 112 setTls((boolean) value);
113 return; 113 break;
114 if (url.startsWith("jdbc:")) 114 case HOST:
115 url = url.substring(5); 115 setHost((String) value);
116 if (url.equals("monetdb:")) { 116 break;
117 return; 117 case PORT:
118 } 118 setPort((int) value);
119 MonetUrlParser.parse(this, url); 119 break;
120 } 120 case DATABASE:
121 121 setDatabase((String) value);
122 private void assign(Parameter parm, Object value) { 122 break;
123 switch (parm) { 123 case TABLESCHEMA:
124 case TLS: setTls((boolean)value); break; 124 setTableschema((String) value);
125 case HOST: setHost((String)value); break; 125 break;
126 case PORT: setPort((int)value); break; 126 case TABLE:
127 case DATABASE: setDatabase((String)value); break; 127 setTable((String) value);
128 case TABLESCHEMA: setTableschema((String)value); break; 128 break;
129 case TABLE: setTable((String)value); break; 129 case SOCK:
130 case SOCK: setSock((String)value); break; 130 setSock((String) value);
131 case SOCKDIR: setSockdir((String)value); break; 131 break;
132 case CERT: setCert((String)value); break; 132 case SOCKDIR:
133 case CERTHASH: setCerthash((String)value); break; 133 setSockdir((String) value);
134 case CLIENTKEY: setClientkey((String)value); break; 134 break;
135 case CLIENTCERT: setClientcert((String)value); break; 135 case CERT:
136 case USER: setUser((String)value); break; 136 setCert((String) value);
137 case PASSWORD: setPassword((String)value); break; 137 break;
138 case LANGUAGE: setLanguage((String)value); break; 138 case CERTHASH:
139 case AUTOCOMMIT: setAutocommit((boolean)value); break; 139 setCerthash((String) value);
140 case SCHEMA: setSchema((String)value); break; 140 break;
141 case TIMEZONE: setTimezone((int)value); break; 141 case CLIENTKEY:
142 case BINARY: setBinary((String)value); break; 142 setClientkey((String) value);
143 case REPLYSIZE: setReplySize((int)value); break; 143 break;
144 case FETCHSIZE: setReplySize((int)value); break; 144 case CLIENTCERT:
145 case HASH: setHash((String)value); break; 145 setClientcert((String) value);
146 case DEBUG: setDebug((boolean)value); break; 146 break;
147 case LOGFILE: setLogfile((String)value); break; 147 case USER:
148 148 setUser((String) value);
149 case SO_TIMEOUT: setSoTimeout((int)value); break; 149 break;
150 case CLOB_AS_VARCHAR: setTreatClobAsVarchar((boolean)value); break; 150 case PASSWORD:
151 case BLOB_AS_BINARY: setTreatBlobAsBinary((boolean)value); break; 151 setPassword((String) value);
152 152 break;
153 default: 153 case LANGUAGE:
154 throw new IllegalStateException("unreachable -- missing case: " + parm.name); 154 setLanguage((String) value);
155 } 155 break;
156 } 156 case AUTOCOMMIT:
157 157 setAutocommit((boolean) value);
158 public String getString(Parameter parm) { 158 break;
159 Object value = getObject(parm); 159 case SCHEMA:
160 return parm.type.format(value); 160 setSchema((String) value);
161 } 161 break;
162 162 case TIMEZONE:
163 public Object getObject(Parameter parm) { 163 setTimezone((int) value);
164 switch (parm) { 164 break;
165 case TLS: return tls; 165 case BINARY:
166 case HOST: return host; 166 setBinary((String) value);
167 case PORT: return port; 167 break;
168 case DATABASE: return database; 168 case REPLYSIZE:
169 case TABLESCHEMA: return tableschema; 169 setReplySize((int) value);
170 case TABLE: return table; 170 break;
171 case SOCK: return sock; 171 case FETCHSIZE:
172 case SOCKDIR: return sockdir; 172 setReplySize((int) value);
173 case CERT: return cert; 173 break;
174 case CERTHASH: return certhash; 174 case HASH:
175 case CLIENTKEY: return clientkey; 175 setHash((String) value);
176 case CLIENTCERT: return clientcert; 176 break;
177 case USER: return user; 177 case DEBUG:
178 case PASSWORD: return password; 178 setDebug((boolean) value);
179 case LANGUAGE: return language; 179 break;
180 case AUTOCOMMIT: return autocommit; 180 case LOGFILE:
181 case SCHEMA: return schema; 181 setLogfile((String) value);
182 case TIMEZONE: return timezone; 182 break;
183 case BINARY: return binary; 183
184 case REPLYSIZE: return replySize; 184 case SO_TIMEOUT:
185 case FETCHSIZE: return replySize; 185 setSoTimeout((int) value);
186 case HASH: return hash; 186 break;
187 case DEBUG: return debug; 187 case CLOB_AS_VARCHAR:
188 case LOGFILE: return logfile; 188 setTreatClobAsVarchar((boolean) value);
189 case SO_TIMEOUT: return soTimeout; 189 break;
190 case CLOB_AS_VARCHAR: return treatClobAsVarchar; 190 case BLOB_AS_BINARY:
191 case BLOB_AS_BINARY: return treatBlobAsBinary; 191 setTreatBlobAsBinary((boolean) value);
192 default: 192 break;
193 throw new IllegalStateException("unreachable -- missing case"); 193
194 } 194 default:
195 } 195 throw new IllegalStateException("unreachable -- missing case: " + parm.name);
196 196 }
197 public boolean isTls() { 197 }
198 return tls; 198
199 } 199 public String getString(Parameter parm) {
200 200 Object value = getObject(parm);
201 public void setTls(boolean tls) { 201 return parm.type.format(value);
202 this.tls = tls; 202 }
203 validated = null; 203
204 } 204 public Object getObject(Parameter parm) {
205 205 switch (parm) {
206 public String getHost() { 206 case TLS:
207 return host; 207 return tls;
208 } 208 case HOST:
209 209 return host;
210 public void setHost(String host) { 210 case PORT:
211 this.host = host; 211 return port;
212 validated = null; 212 case DATABASE:
213 } 213 return database;
214 214 case TABLESCHEMA:
215 public int getPort() { 215 return tableschema;
216 return port; 216 case TABLE:
217 } 217 return table;
218 218 case SOCK:
219 public void setPort(int port) { 219 return sock;
220 this.port = port; 220 case SOCKDIR:
221 validated = null; 221 return sockdir;
222 } 222 case CERT:
223 223 return cert;
224 public String getDatabase() { 224 case CERTHASH:
225 return database; 225 return certhash;
226 } 226 case CLIENTKEY:
227 227 return clientkey;
228 public void setDatabase(String database) { 228 case CLIENTCERT:
229 this.database = database; 229 return clientcert;
230 validated = null; 230 case USER:
231 } 231 return user;
232 232 case PASSWORD:
233 public String getTableschema() { 233 return password;
234 return tableschema; 234 case LANGUAGE:
235 } 235 return language;
236 236 case AUTOCOMMIT:
237 public void setTableschema(String tableschema) { 237 return autocommit;
238 this.tableschema = tableschema; 238 case SCHEMA:
239 validated = null; 239 return schema;
240 } 240 case TIMEZONE:
241 241 return timezone;
242 public String getTable() { 242 case BINARY:
243 return table; 243 return binary;
244 } 244 case REPLYSIZE:
245 245 return replySize;
246 public void setTable(String table) { 246 case FETCHSIZE:
247 this.table = table; 247 return replySize;
248 validated = null; 248 case HASH:
249 } 249 return hash;
250 250 case DEBUG:
251 public String getSock() { 251 return debug;
252 return sock; 252 case LOGFILE:
253 } 253 return logfile;
254 254 case SO_TIMEOUT:
255 public void setSock(String sock) { 255 return soTimeout;
256 this.sock = sock; 256 case CLOB_AS_VARCHAR:
257 validated = null; 257 return treatClobAsVarchar;
258 } 258 case BLOB_AS_BINARY:
259 259 return treatBlobAsBinary;
260 public String getSockdir() { 260 default:
261 return sockdir; 261 throw new IllegalStateException("unreachable -- missing case");
262 } 262 }
263 263 }
264 public void setSockdir(String sockdir) { 264
265 this.sockdir = sockdir; 265 public boolean isTls() {
266 validated = null; 266 return tls;
267 } 267 }
268 268
269 public String getCert() { 269 public void setTls(boolean tls) {
270 return cert; 270 this.tls = tls;
271 } 271 validated = null;
272 272 }
273 public void setCert(String cert) { 273
274 this.cert = cert; 274 public String getHost() {
275 validated = null; 275 return host;
276 } 276 }
277 277
278 public String getCerthash() { 278 public void setHost(String host) {
279 return certhash; 279 this.host = host;
280 } 280 validated = null;
281 281 }
282 public void setCerthash(String certhash) { 282
283 this.certhash = certhash; 283 public int getPort() {
284 validated = null; 284 return port;
285 } 285 }
286 286
287 public String getClientkey() { 287 public void setPort(int port) {
288 return clientkey; 288 this.port = port;
289 } 289 validated = null;
290 290 }
291 public void setClientkey(String clientkey) { 291
292 this.clientkey = clientkey; 292 public String getDatabase() {
293 validated = null; 293 return database;
294 } 294 }
295 295
296 public String getClientcert() { 296 public void setDatabase(String database) {
297 return clientcert; 297 this.database = database;
298 } 298 validated = null;
299 299 }
300 public void setClientcert(String clientcert) { 300
301 this.clientcert = clientcert; 301 public String getTableschema() {
302 validated = null; 302 return tableschema;
303 } 303 }
304 304
305 public String getUser() { 305 public void setTableschema(String tableschema) {
306 return user; 306 this.tableschema = tableschema;
307 } 307 validated = null;
308 308 }
309 public void setUser(String user) { 309
310 this.user = user; 310 public String getTable() {
311 this.userWasSet = true; 311 return table;
312 validated = null; 312 }
313 } 313
314 314 public void setTable(String table) {
315 public String getPassword() { 315 this.table = table;
316 return password; 316 validated = null;
317 } 317 }
318 318
319 public void setPassword(String password) { 319 public String getSock() {
320 this.password = password; 320 return sock;
321 this.passwordWasSet = true; 321 }
322 validated = null; 322
323 } 323 public void setSock(String sock) {
324 324 this.sock = sock;
325 public String getLanguage() { 325 validated = null;
326 return language; 326 }
327 } 327
328 328 public String getSockdir() {
329 public void setLanguage(String language) { 329 return sockdir;
330 this.language = language; 330 }
331 validated = null; 331
332 } 332 public void setSockdir(String sockdir) {
333 333 this.sockdir = sockdir;
334 public boolean isAutocommit() { 334 validated = null;
335 return autocommit; 335 }
336 } 336
337 337 public String getCert() {
338 public void setAutocommit(boolean autocommit) { 338 return cert;
339 this.autocommit = autocommit; 339 }
340 validated = null; 340
341 } 341 public void setCert(String cert) {
342 342 this.cert = cert;
343 public String getSchema() { 343 validated = null;
344 return schema; 344 }
345 } 345
346 346 public String getCerthash() {
347 public void setSchema(String schema) { 347 return certhash;
348 this.schema = schema; 348 }
349 validated = null; 349
350 } 350 public void setCerthash(String certhash) {
351 351 this.certhash = certhash;
352 public int getTimezone() { 352 validated = null;
353 return timezone; 353 }
354 } 354
355 355 public String getClientkey() {
356 public void setTimezone(int timezone) { 356 return clientkey;
357 this.timezone = timezone; 357 }
358 validated = null; 358
359 } 359 public void setClientkey(String clientkey) {
360 360 this.clientkey = clientkey;
361 public String getBinary() { 361 validated = null;
362 return binary; 362 }
363 } 363
364 364 public String getClientcert() {
365 public void setBinary(String binary) { 365 return clientcert;
366 this.binary = binary; 366 }
367 validated = null; 367
368 } 368 public void setClientcert(String clientcert) {
369 369 this.clientcert = clientcert;
370 public int getReplySize() { 370 validated = null;
371 return replySize; 371 }
372 } 372
373 373 public String getUser() {
374 public void setReplySize(int replySize) { 374 return user;
375 this.replySize = replySize; 375 }
376 validated = null; 376
377 } 377 public void setUser(String user) {
378 378 this.user = user;
379 public String getHash() { 379 this.userWasSet = true;
380 return hash; 380 validated = null;
381 } 381 }
382 382
383 public void setHash(String hash) { 383 public String getPassword() {
384 this.hash = hash; 384 return password;
385 validated = null; 385 }
386 } 386
387 387 public void setPassword(String password) {
388 public boolean isDebug() { 388 this.password = password;
389 return debug; 389 this.passwordWasSet = true;
390 } 390 validated = null;
391 391 }
392 public void setDebug(boolean debug) { 392
393 this.debug = debug; 393 public String getLanguage() {
394 validated = null; 394 return language;
395 } 395 }
396 396
397 public String getLogfile() { 397 public void setLanguage(String language) {
398 return logfile; 398 this.language = language;
399 } 399 validated = null;
400 400 }
401 public void setLogfile(String logfile) { 401
402 this.logfile = logfile; 402 public boolean isAutocommit() {
403 validated = null; 403 return autocommit;
404 } 404 }
405 405
406 public int getSoTimeout() { 406 public void setAutocommit(boolean autocommit) {
407 return soTimeout; 407 this.autocommit = autocommit;
408 } 408 validated = null;
409 409 }
410 410
411 public void setSoTimeout(int soTimeout) { 411 public String getSchema() {
412 this.soTimeout = soTimeout; 412 return schema;
413 validated = null; 413 }
414 } 414
415 415 public void setSchema(String schema) {
416 public void setTreatClobAsVarchar(boolean treatClobAsVarchar) { 416 this.schema = schema;
417 this.treatClobAsVarchar = treatClobAsVarchar; 417 validated = null;
418 validated = null; 418 }
419 } 419
420 420 public int getTimezone() {
421 public boolean isTreatClobAsVarchar() { 421 return timezone;
422 return treatClobAsVarchar; 422 }
423 } 423
424 424 public void setTimezone(int timezone) {
425 public boolean isTreatBlobAsBinary() { 425 this.timezone = timezone;
426 return treatBlobAsBinary; 426 validated = null;
427 } 427 }
428 428
429 public void setTreatBlobAsBinary(boolean treatBlobAsBinary) { 429 public String getBinary() {
430 this.treatBlobAsBinary = treatBlobAsBinary; 430 return binary;
431 validated = null; 431 }
432 } 432
433 433 public void setBinary(String binary) {
434 public Validated validate() throws ValidationError { 434 this.binary = binary;
435 if (validated == null) 435 validated = null;
436 validated = new Validated(); 436 }
437 return validated; 437
438 } 438 public int getReplySize() {
439 439 return replySize;
440 public String buildUrl() { 440 }
441 final StringBuilder sb = new StringBuilder(128); 441
442 sb.append("jdbc:"); 442 public void setReplySize(int replySize) {
443 sb.append(tls ? "monetdbs": "monetdb"); 443 this.replySize = replySize;
444 sb.append("://"); 444 validated = null;
445 sb.append(packHost(host)); 445 }
446 if (!Parameter.PORT.getDefault().equals(port)) { 446
447 sb.append(':'); 447 public String getHash() {
448 sb.append(port); 448 return hash;
449 } 449 }
450 sb.append('/').append(database); 450
451 String sep = "?"; 451 public void setHash(String hash) {
452 for (Parameter parm: Parameter.values()) { 452 this.hash = hash;
453 if (parm.isCore || parm == Parameter.USER || parm == Parameter.PASSWORD) 453 validated = null;
454 continue; 454 }
455 Object defaultValue = parm.getDefault(); 455
456 if (defaultValue == null) 456 public boolean isDebug() {
457 continue; 457 return debug;
458 Object value = getObject(parm); 458 }
459 if (value.equals(defaultValue)) 459
460 continue; 460 public void setDebug(boolean debug) {
461 sb.append(sep).append(parm.name).append('='); 461 this.debug = debug;
462 String raw = getString(parm); 462 validated = null;
463 String encoded = MonetUrlParser.percentEncode(raw); 463 }
464 sb.append(encoded); 464
465 sep = "&"; 465 public String getLogfile() {
466 } 466 return logfile;
467 return sb.toString(); 467 }
468 } 468
469 469 public void setLogfile(String logfile) {
470 public Properties getProperties() { 470 this.logfile = logfile;
471 Properties props = new Properties(); 471 validated = null;
472 for (Parameter parm: Parameter.values()) { 472 }
473 Object defaultValue = parm.getDefault(); 473
474 if (defaultValue == null || defaultValue.equals(getObject(parm))) 474 public int getSoTimeout() {
475 continue; 475 return soTimeout;
476 String value = getString(parm); 476 }
477 if (parm == Parameter.HOST) 477
478 value = packHost(host); 478 public void setSoTimeout(int soTimeout) {
479 props.setProperty(parm.name, value); 479 this.soTimeout = soTimeout;
480 } 480 validated = null;
481 481 }
482 return props; 482
483 } 483 public boolean isTreatClobAsVarchar() {
484 484 return treatClobAsVarchar;
485 public class Validated { 485 }
486 486
487 private final int nbinary; 487 public void setTreatClobAsVarchar(boolean treatClobAsVarchar) {
488 488 this.treatClobAsVarchar = treatClobAsVarchar;
489 Validated() throws ValidationError { 489 validated = null;
490 490 }
491 // 1. The parameters have the types listed in the table in [Section 491
492 // Parameters](#parameters). 492 public boolean isTreatBlobAsBinary() {
493 493 return treatBlobAsBinary;
494 String binaryString = binary; 494 }
495 int binaryInt; 495
496 try { 496 public void setTreatBlobAsBinary(boolean treatBlobAsBinary) {
497 binaryInt = (int) ParameterType.Int.parse(Parameter.BINARY.name, binaryString); 497 this.treatBlobAsBinary = treatBlobAsBinary;
498 } catch (ValidationError e) { 498 validated = null;
499 try { 499 }
500 boolean b = (boolean) ParameterType.Bool.parse(Parameter.BINARY.name, binaryString); 500
501 binaryInt = b ? 65535 : 0; 501 public Validated validate() throws ValidationError {
502 } catch (ValidationError ee) { 502 if (validated == null)
503 throw new ValidationError("binary= must be either a number or true/yes/on/false/no/off"); 503 validated = new Validated();
504 } 504 return validated;
505 } 505 }
506 if (binaryInt < 0) 506
507 throw new ValidationError("binary= cannot be negative"); 507 public String buildUrl() {
508 nbinary = binaryInt; 508 final StringBuilder sb = new StringBuilder(128);
509 509 sb.append("jdbc:");
510 510 sb.append(tls ? "monetdbs" : "monetdb");
511 // 2. At least one of **sock** and **host** must be empty. 511 sb.append("://");
512 if (!sock.isEmpty() && !host.isEmpty()) 512 sb.append(packHost(host));
513 throw new ValidationError("sock=" + sock + " cannot be combined with host=" + host); 513 if (!Parameter.PORT.getDefault().equals(port)) {
514 514 sb.append(':');
515 // 3. The string parameter **binary** must either parse as a boolean or as a 515 sb.append(port);
516 // non-negative integer. 516 }
517 // 517 sb.append('/').append(database);
518 // (checked above) 518 String sep = "?";
519 519 for (Parameter parm : Parameter.values()) {
520 // 4. If **sock** is not empty, **tls** must be 'off'. 520 if (parm.isCore || parm == Parameter.USER || parm == Parameter.PASSWORD)
521 if (!sock.isEmpty() && tls) throw new ValidationError("monetdbs:// cannot be combined with sock="); 521 continue;
522 522 Object defaultValue = parm.getDefault();
523 // 5. If **certhash** is not empty, it must be of the form `{sha256}hexdigits` 523 if (defaultValue == null)
524 // where hexdigits is a non-empty sequence of 0-9, a-f, A-F and colons. 524 continue;
525 // TODO 525 Object value = getObject(parm);
526 if (!certhash.isEmpty()) { 526 if (value.equals(defaultValue))
527 if (!certhash.toLowerCase().startsWith("sha256:")) 527 continue;
528 throw new ValidationError("certificate hash must start with 'sha256:'"); 528 sb.append(sep).append(parm.name).append('=');
529 if (!hashPattern.matcher(certhash).matches()) 529 String raw = getString(parm);
530 throw new ValidationError("invalid certificate hash"); 530 String encoded = MonetUrlParser.percentEncode(raw);
531 } 531 sb.append(encoded);
532 532 sep = "&";
533 // 6. If **tls** is 'off', **cert** and **certhash** must be 'off' as well. 533 }
534 if (!tls) { 534 return sb.toString();
535 if (!cert.isEmpty() || !certhash.isEmpty()) 535 }
536 throw new ValidationError("cert= and certhash= are only allowed in combination with monetdbs://"); 536
537 } 537 public Properties getProperties() {
538 538 Properties props = new Properties();
539 // 7. Parameters **database**, **tableschema** and **table** must consist only of 539 for (Parameter parm : Parameter.values()) {
540 // upper- and lowercase letters, digits, periods, dashes and underscores. They must not 540 Object defaultValue = parm.getDefault();
541 // start with a dash. 541 if (defaultValue == null || defaultValue.equals(getObject(parm)))
542 // If **table** is not empty, **tableschema** must also not be empty. 542 continue;
543 // If **tableschema** is not empty, **database** must also not be empty. 543 String value = getString(parm);
544 if (database.isEmpty() && !tableschema.isEmpty()) 544 if (parm == Parameter.HOST)
545 throw new ValidationError("table schema cannot be set without database"); 545 value = packHost(host);
546 if (tableschema.isEmpty() && !table.isEmpty()) 546 props.setProperty(parm.name, value);
547 throw new ValidationError("table cannot be set without schema"); 547 }
548 if (!database.isEmpty() && !namePattern.matcher(database).matches()) 548
549 throw new ValidationError("invalid database name"); 549 return props;
550 if (!tableschema.isEmpty() && !namePattern.matcher(tableschema).matches()) 550 }
551 throw new ValidationError("invalid table schema name"); 551
552 if (!table.isEmpty() && !namePattern.matcher(table).matches()) 552 public void setProperties(Properties props) throws ValidationError {
553 throw new ValidationError("invalid table name"); 553 if (props != null) {
554 554 for (String key : props.stringPropertyNames()) {
555 555 String value = props.getProperty(key);
556 // 8. Parameter **port** must be -1 or in the range 1-65535. 556 if (key.equals(Parameter.HOST.name))
557 if (port < -1 || port == 0 || port > 65535) throw new ValidationError("invalid port number " + port); 557 value = Target.unpackHost(value);
558 558 setString(key, value);
559 // 9. If **clientcert** is set, **clientkey** must also be set. 559 }
560 if (!clientcert.isEmpty() && clientkey.isEmpty()) 560 }
561 throw new ValidationError("clientcert= is only valid in combination with clientkey="); 561 }
562 562
563 // JDBC specific 563 public enum Verify {
564 if (soTimeout < 0) 564 None, Cert, Hash, System
565 throw new ValidationError("so_timeout= must not be negative"); 565 }
566 } 566
567 567 public class Validated {
568 public boolean getTls() { 568
569 return tls; 569 private final int nbinary;
570 } 570
571 571 Validated() throws ValidationError {
572 // Getter is private because you probably want connectTcp() instead 572
573 private String getHost() { 573 // 1. The parameters have the types listed in the table in [Section
574 return host; 574 // Parameters](#parameters).
575 } 575
576 576 String binaryString = binary;
577 // Getter is private because you probably want connectPort() instead 577 int binaryInt;
578 private int getPort() { 578 try {
579 return port; 579 binaryInt = (int) ParameterType.Int.parse(Parameter.BINARY.name, binaryString);
580 } 580 } catch (ValidationError e) {
581 581 try {
582 public String getDatabase() { 582 boolean b = (boolean) ParameterType.Bool.parse(Parameter.BINARY.name, binaryString);
583 return database; 583 binaryInt = b ? 65535 : 0;
584 } 584 } catch (ValidationError ee) {
585 585 throw new ValidationError("binary= must be either a number or true/yes/on/false/no/off");
586 public String getTableschema() { 586 }
587 return tableschema; 587 }
588 } 588 if (binaryInt < 0)
589 589 throw new ValidationError("binary= cannot be negative");
590 public String getTable() { 590 nbinary = binaryInt;
591 return table; 591
592 } 592
593 593 // 2. At least one of **sock** and **host** must be empty.
594 // Getter is private because you probably want connectUnix() instead 594 if (!sock.isEmpty() && !host.isEmpty())
595 private String getSock() { 595 throw new ValidationError("sock=" + sock + " cannot be combined with host=" + host);
596 return sock; 596
597 } 597 // 3. The string parameter **binary** must either parse as a boolean or as a
598 598 // non-negative integer.
599 public String getSockdir() { 599 //
600 return sockdir; 600 // (checked above)
601 } 601
602 602 // 4. If **sock** is not empty, **tls** must be 'off'.
603 public String getCert() { 603 if (!sock.isEmpty() && tls)
604 return cert; 604 throw new ValidationError("monetdbs:// cannot be combined with sock=");
605 } 605
606 606 // 5. If **certhash** is not empty, it must be of the form `{sha256}hexdigits`
607 public String getCerthash() { 607 // where hexdigits is a non-empty sequence of 0-9, a-f, A-F and colons.
608 return certhash; 608 // TODO
609 } 609 if (!certhash.isEmpty()) {
610 610 if (!certhash.toLowerCase().startsWith("sha256:"))
611 public String getClientkey() { 611 throw new ValidationError("certificate hash must start with 'sha256:'");
612 return clientkey; 612 if (!hashPattern.matcher(certhash).matches())
613 } 613 throw new ValidationError("invalid certificate hash");
614 614 }
615 public String getClientcert() { 615
616 return clientcert; 616 // 6. If **tls** is 'off', **cert** and **certhash** must be 'off' as well.
617 } 617 if (!tls) {
618 618 if (!cert.isEmpty() || !certhash.isEmpty())
619 public String getUser() { 619 throw new ValidationError("cert= and certhash= are only allowed in combination with monetdbs://");
620 return user; 620 }
621 } 621
622 622 // 7. Parameters **database**, **tableschema** and **table** must consist only of
623 public String getPassword() { 623 // upper- and lowercase letters, digits, periods, dashes and underscores. They must not
624 return password; 624 // start with a dash.
625 } 625 // If **table** is not empty, **tableschema** must also not be empty.
626 626 // If **tableschema** is not empty, **database** must also not be empty.
627 public String getLanguage() { 627 if (database.isEmpty() && !tableschema.isEmpty())
628 return language; 628 throw new ValidationError("table schema cannot be set without database");
629 } 629 if (tableschema.isEmpty() && !table.isEmpty())
630 630 throw new ValidationError("table cannot be set without schema");
631 public boolean getAutocommit() { 631 if (!database.isEmpty() && !namePattern.matcher(database).matches())
632 return autocommit; 632 throw new ValidationError("invalid database name");
633 } 633 if (!tableschema.isEmpty() && !namePattern.matcher(tableschema).matches())
634 634 throw new ValidationError("invalid table schema name");
635 public String getSchema() { 635 if (!table.isEmpty() && !namePattern.matcher(table).matches())
636 return schema; 636 throw new ValidationError("invalid table name");
637 } 637
638 638
639 public int getTimezone() { 639 // 8. Parameter **port** must be -1 or in the range 1-65535.
640 return timezone; 640 if (port < -1 || port == 0 || port > 65535)
641 } 641 throw new ValidationError("invalid port number " + port);
642 642
643 // Getter is private because you probably want connectBinary() instead 643 // 9. If **clientcert** is set, **clientkey** must also be set.
644 public int getBinary() { 644 if (!clientcert.isEmpty() && clientkey.isEmpty())
645 return nbinary; 645 throw new ValidationError("clientcert= is only valid in combination with clientkey=");
646 } 646
647 647 // JDBC specific
648 public int getReplySize() { 648 if (soTimeout < 0)
649 return replySize; 649 throw new ValidationError("so_timeout= must not be negative");
650 } 650 }
651 651
652 public String getHash() { 652 public boolean getTls() {
653 return hash; 653 return tls;
654 } 654 }
655 655
656 public boolean getDebug() { 656 // Getter is private because you probably want connectTcp() instead
657 return debug; 657 private String getHost() {
658 } 658 return host;
659 659 }
660 public String getLogfile() { 660
661 return logfile; 661 // Getter is private because you probably want connectPort() instead
662 } 662 private int getPort() {
663 663 return port;
664 public int getSoTimeout() { 664 }
665 return soTimeout; 665
666 } 666 public String getDatabase() {
667 667 return database;
668 public boolean isTreatClobAsVarchar() { 668 }
669 return treatClobAsVarchar; 669
670 } 670 public String getTableschema() {
671 671 return tableschema;
672 public boolean isTreatBlobAsBinary() { 672 }
673 return treatBlobAsBinary; 673
674 } 674 public String getTable() {
675 675 return table;
676 public boolean connectScan() { 676 }
677 if (database.isEmpty()) return false; 677
678 if (!sock.isEmpty() || !host.isEmpty() || port != -1) return false; 678 // Getter is private because you probably want connectUnix() instead
679 return !tls; 679 private String getSock() {
680 } 680 return sock;
681 681 }
682 public int connectPort() { 682
683 return port == -1 ? 50000 : port; 683 public String getSockdir() {
684 } 684 return sockdir;
685 685 }
686 public String connectUnix() { 686
687 if (!sock.isEmpty()) return sock; 687 public String getCert() {
688 if (tls) return ""; 688 return cert;
689 if (host.isEmpty()) return sockdir + "/.s.monetdb." + connectPort(); 689 }
690 return ""; 690
691 } 691 public String getCerthash() {
692 692 return certhash;
693 public String connectTcp() { 693 }
694 if (!sock.isEmpty()) return ""; 694
695 if (host.isEmpty()) return "localhost"; 695 public String getClientkey() {
696 return host; 696 return clientkey;
697 } 697 }
698 698
699 public Verify connectVerify() { 699 public String getClientcert() {
700 if (!tls) return Verify.None; 700 return clientcert;
701 if (!certhash.isEmpty()) return Verify.Hash; 701 }
702 if (!cert.isEmpty()) return Verify.Cert; 702
703 return Verify.System; 703 public String getUser() {
704 } 704 return user;
705 705 }
706 public String connectCertHashDigits() { 706
707 if (!tls) return null; 707 public String getPassword() {
708 StringBuilder builder = new StringBuilder(certhash.length()); 708 return password;
709 for (int i = "sha256:".length(); i < certhash.length(); i++) { 709 }
710 char c = certhash.charAt(i); 710
711 if (Character.digit(c, 16) >= 0) builder.append(Character.toLowerCase(c)); 711 public String getLanguage() {
712 } 712 return language;
713 return builder.toString(); 713 }
714 } 714
715 715 public boolean getAutocommit() {
716 public int connectBinary() { 716 return autocommit;
717 return nbinary; 717 }
718 } 718
719 719 public String getSchema() {
720 public String connectClientKey() { 720 return schema;
721 return clientkey; 721 }
722 } 722
723 723 public int getTimezone() {
724 public String connectClientCert() { 724 return timezone;
725 return clientcert.isEmpty() ? clientkey : clientcert; 725 }
726 } 726
727 } 727 // Getter is private because you probably want connectBinary() instead
728 728 public int getBinary() {
729 public enum Verify { 729 return nbinary;
730 None, 730 }
731 Cert, 731
732 Hash, 732 public int getReplySize() {
733 System; 733 return replySize;
734 } 734 }
735
736 public String getHash() {
737 return hash;
738 }
739
740 public boolean getDebug() {
741 return debug;
742 }
743
744 public String getLogfile() {
745 return logfile;
746 }
747
748 public int getSoTimeout() {
749 return soTimeout;
750 }
751
752 public boolean isTreatClobAsVarchar() {
753 return treatClobAsVarchar;
754 }
755
756 public boolean isTreatBlobAsBinary() {
757 return treatBlobAsBinary;
758 }
759
760 public boolean connectScan() {
761 if (database.isEmpty())
762 return false;
763 if (!sock.isEmpty() || !host.isEmpty() || port != -1)
764 return false;
765 return !tls;
766 }
767
768 public int connectPort() {
769 return port == -1 ? 50000 : port;
770 }
771
772 public String connectUnix() {
773 if (!sock.isEmpty())
774 return sock;
775 if (tls)
776 return "";
777 if (host.isEmpty())
778 return sockdir + "/.s.monetdb." + connectPort();
779 return "";
780 }
781
782 public String connectTcp() {
783 if (!sock.isEmpty())
784 return "";
785 if (host.isEmpty())
786 return "localhost";
787 return host;
788 }
789
790 public Verify connectVerify() {
791 if (!tls)
792 return Verify.None;
793 if (!certhash.isEmpty())
794 return Verify.Hash;
795 if (!cert.isEmpty())
796 return Verify.Cert;
797 return Verify.System;
798 }
799
800 public String connectCertHashDigits() {
801 if (!tls)
802 return null;
803 StringBuilder builder = new StringBuilder(certhash.length());
804 for (int i = "sha256:".length(); i < certhash.length(); i++) {
805 char c = certhash.charAt(i);
806 if (Character.digit(c, 16) >= 0)
807 builder.append(Character.toLowerCase(c));
808 }
809 return builder.toString();
810 }
811
812 public int connectBinary() {
813 return nbinary;
814 }
815
816 public String connectClientKey() {
817 return clientkey;
818 }
819
820 public String connectClientCert() {
821 return clientcert.isEmpty() ? clientkey : clientcert;
822 }
823 }
735 } 824 }