OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 142 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
182 ilm 4
 * Copyright 2011-2019 OpenConcerto, by ILM Informatique. All rights reserved.
17 ilm 5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 /*
15
 * Created on 7 mai 03
16
 */
17
package org.openconcerto.sql.model;
18
 
63 ilm 19
import org.openconcerto.sql.model.LoadingListener.StructureLoadingEvent;
67 ilm 20
import org.openconcerto.sql.model.graph.TablesMap;
17 ilm 21
import org.openconcerto.sql.utils.SQL_URL;
22
import org.openconcerto.utils.CollectionUtils;
182 ilm 23
import org.openconcerto.utils.NetUtils;
24
import org.openconcerto.utils.Tuple2.List2;
61 ilm 25
import org.openconcerto.utils.cc.CopyOnWriteMap;
17 ilm 26
import org.openconcerto.utils.cc.IClosure;
27
import org.openconcerto.utils.cc.ITransformer;
28
import org.openconcerto.utils.change.CollectionChangeEventCreator;
29
 
80 ilm 30
import java.security.AccessController;
31
import java.security.PrivilegedAction;
63 ilm 32
import java.sql.Connection;
17 ilm 33
import java.sql.SQLException;
34
import java.util.ArrayList;
35
import java.util.Collection;
36
import java.util.Collections;
67 ilm 37
import java.util.HashMap;
17 ilm 38
import java.util.HashSet;
39
import java.util.List;
40
import java.util.Map;
41
import java.util.Set;
65 ilm 42
import java.util.concurrent.Callable;
17 ilm 43
 
61 ilm 44
import net.jcip.annotations.GuardedBy;
45
 
17 ilm 46
/**
47
 * Un serveur de base de donnée SQL. Meaning a system (eg mysql) on a certain host and port. Un
48
 * serveur permet d'accéder aux bases qui le composent (une base par défaut peut être spécifiée). De
49
 * plus il permet de spécifier un login/pass par défaut.
50
 *
51
 * @author ilm
61 ilm 52
 * @see #getOrCreateBase(String)
17 ilm 53
 */
54
public final class SQLServer extends DBStructureItemJDBC {
55
 
61 ilm 56
    private static final IClosure<SQLDataSource> DSINIT_ERROR = new IClosure<SQLDataSource>() {
57
        @Override
58
        public void executeChecked(SQLDataSource input) {
59
            throw new IllegalStateException("Datasource should already be created");
60
        }
61
    };
62
 
83 ilm 63
    static private final <T> IClosure<? super T> coalesce(IClosure<? super T> o1, IClosure<? super T> o2) {
64
        // ternary operator makes Eclipse fail
65
        if (o1 != null)
66
            return o1;
67
        else
68
            return o2;
69
    }
70
 
17 ilm 71
    public static final DBSystemRoot create(final SQL_URL url) {
72
        return create(url, Collections.<String> emptySet(), null);
73
    }
74
 
75
    /**
76
     * Create a system root from the passed URL.
77
     *
78
     * @param url an SQL URL.
65 ilm 79
     * @param rootsToMap the collection of {@link DBSystemRoot#setRootsToMap(Collection) roots to
80
     *        map}, in addition to <code>url.{@link SQL_URL#getRootName() getRootName()}</code>.
17 ilm 81
     * @param dsInit to initialize the datasource before any request (e.g. setting JDBC properties),
82
     *        can be <code>null</code>.
83
     * @return the new system root.
84
     */
85
    public static final DBSystemRoot create(final SQL_URL url, final Collection<String> rootsToMap, IClosure<SQLDataSource> dsInit) {
86
        return create(url, rootsToMap, false, dsInit);
87
    }
88
 
89
    public static final DBSystemRoot create(final SQL_URL url, final Collection<String> roots, final boolean setPath, IClosure<SQLDataSource> dsInit) {
90
        final DBSystemRoot res = create(url, new IClosure<DBSystemRoot>() {
91
            @Override
92
            public void executeChecked(DBSystemRoot input) {
93 ilm 93
                if (url.getRootName() != null) {
94
                    input.setRootToMap(url.getRootName());
95
                    input.addRootsToMap(roots);
96
                } else {
97
                    input.setRootsToMap(roots);
98
                }
17 ilm 99
            }
100
        }, dsInit);
101
        if (setPath) {
102
            final List<String> path = new ArrayList<String>(roots);
93 ilm 103
            if (url.getRootName() != null)
104
                path.add(0, url.getRootName());
17 ilm 105
            path.retainAll(res.getChildrenNames());
106
            if (path.size() > 0)
107
                res.setRootPath(path);
108
        }
109
        return res;
110
    }
111
 
83 ilm 112
    public static final DBSystemRoot create(final SQL_URL url, final IClosure<? super DBSystemRoot> systemRootInit, final IClosure<? super SQLDataSource> dsInit) {
65 ilm 113
        return new SQLServer(url.getSystem(), url.getServerName(), null, url.getLogin(), url.getPass(), systemRootInit, dsInit).getSystemRoot(url.getSystemRootName());
17 ilm 114
    }
115
 
116
    // *** Instance members
117
 
118
    // eg mysql, derby
119
    private final SQLSystem system;
120
    private final String login;
121
    private final String pass;
83 ilm 122
    private final IClosure<? super DBSystemRoot> systemRootInit;
61 ilm 123
    @GuardedBy("baseMutex")
124
    private CopyOnWriteMap<String, SQLBase> bases;
125
    private Object baseMutex = new String("base mutex");
126
    // linked to bases
127
    @GuardedBy("this")
17 ilm 128
    private String defaultBase;
61 ilm 129
    // linked to dsSet
130
    @GuardedBy("this")
17 ilm 131
    private SQLDataSource ds;
61 ilm 132
    @GuardedBy("this")
17 ilm 133
    private boolean dsSet;
83 ilm 134
    private final IClosure<? super SQLDataSource> dsInit;
17 ilm 135
    private final ITransformer<String, String> urlTransf;
136
 
67 ilm 137
    @GuardedBy("this")
138
    private String id;
139
 
65 ilm 140
    public SQLServer(SQLSystem system, String host) {
17 ilm 141
        this(system, host, null);
142
    }
143
 
65 ilm 144
    public SQLServer(SQLSystem system, String host, String port) {
17 ilm 145
        this(system, host, port, null, null);
146
    }
147
 
65 ilm 148
    public SQLServer(SQLSystem system, String host, String port, String login, String pass) {
17 ilm 149
        this(system, host, port, login, pass, null, null);
150
    }
151
 
152
    /**
153
     * Creates a new server.
154
     *
65 ilm 155
     * @param system the database system.
17 ilm 156
     * @param host an IP address or DNS name.
157
     * @param port the port to connect to can be <code>null</code> to pick the system default.
158
     * @param login the default login to access database of this server, can be <code>null</code>.
159
     * @param pass the default password to access database of this server, can be <code>null</code>.
160
     * @param systemRootInit to initialize the system root in its constructor, can be
161
     *        <code>null</code>.
162
     * @param dsInit to initialize the datasource before any request (e.g. setting JDBC properties),
61 ilm 163
     *        must be thread-safe, can be <code>null</code>.
17 ilm 164
     */
83 ilm 165
    public SQLServer(SQLSystem system, String host, String port, String login, String pass, IClosure<? super DBSystemRoot> systemRootInit, IClosure<? super SQLDataSource> dsInit) {
17 ilm 166
        super(null, host);
167
        this.ds = null;
168
        this.dsSet = false;
169
        this.dsInit = dsInit;
65 ilm 170
        this.system = system;
17 ilm 171
        this.login = login;
172
        this.pass = pass;
173
        this.bases = null;
174
        this.systemRootInit = systemRootInit;
175
        this.urlTransf = this.getSQLSystem().getURLTransf(this);
176
 
67 ilm 177
        this.id = this.getName();
178
 
17 ilm 179
        // cannot refetch now as we don't have any datasource yet (see createSystemRoot())
180
    }
181
 
61 ilm 182
    private final CopyOnWriteMap<String, SQLBase> getBases() {
183
        synchronized (this.getTreeMutex()) {
184
            synchronized (this.baseMutex) {
185
                if (this.bases == null) {
186
                    this.checkDropped();
187
                    this.bases = new CopyOnWriteMap<String, SQLBase>();
65 ilm 188
                    this.refresh(null, true, true);
61 ilm 189
                }
190
                return this.bases;
191
            }
17 ilm 192
        }
193
    }
194
 
195
    /**
196
     * Signal that this server and its descendants will not be used anymore.
197
     */
198
    public final void destroy() {
83 ilm 199
        synchronized (this.getTreeMutex()) {
200
            if (!this.isDropped())
201
                this.dropped();
202
        }
17 ilm 203
    }
204
 
205
    @Override
206
    protected void onDrop() {
61 ilm 207
        synchronized (this) {
208
            if (this.ds != null)
209
                try {
210
                    this.ds.close();
211
                } catch (SQLException e) {
212
                    // tant pis
213
                    e.printStackTrace();
214
                }
215
        }
17 ilm 216
        // allow SQLBase to be gc'd even if someone holds on to us
61 ilm 217
        synchronized (this.baseMutex) {
218
            this.bases = null;
219
        }
17 ilm 220
        super.onDrop();
221
    }
222
 
61 ilm 223
    private final Object getTreeMutex() {
224
        final DBSystemRoot sysRoot = this.getDBSystemRoot();
225
        final Object res = sysRoot == null ? this : sysRoot.getTreeMutex();
226
        assert Thread.holdsLock(res) || !Thread.holdsLock(this);
227
        return res;
228
    }
229
 
67 ilm 230
    Map<String, TablesMap> refresh(final Map<String, TablesMap> namesToRefresh, final boolean readCache) {
231
        return this.refresh(namesToRefresh, readCache, false);
17 ilm 232
    }
233
 
67 ilm 234
    // return null if this cannot be refreshed (i.e. this is above DBSystemRoot)
235
    private Map<String, TablesMap> refresh(final Map<String, TablesMap> tablesToRefresh, final boolean readCache, final boolean init) {
17 ilm 236
        if (this.getDS() != null) {
67 ilm 237
            if (Collections.emptyMap().equals(tablesToRefresh))
238
                return tablesToRefresh;
239
            final Set<String> namesToRefresh = tablesToRefresh == null ? null : tablesToRefresh.keySet();
17 ilm 240
            // for mysql we must know our children, since they can reference each other and thus the
241
            // graph needs them
63 ilm 242
            final StructureLoadingEvent evt = new StructureLoadingEvent(this, namesToRefresh);
17 ilm 243
            try {
63 ilm 244
                this.getDBSystemRoot().fireLoading(evt);
61 ilm 245
                synchronized (this.getTreeMutex()) {
246
                    final Set<String> childrenToRefresh = CollectionUtils.inter(namesToRefresh, this.getChildrenNames());
247
                    // don't save the result in files since getCatalogs() is at least as quick as
248
                    // executing a request to check if the cache is obsolete
63 ilm 249
                    final Set<String> allCats;
250
                    final Connection conn = this.getDS().getNewConnection();
251
                    try {
142 ilm 252
                        final List<String> allCatsList = ColumnListHandlerGeneric.create(String.class).handle(conn.getMetaData().getCatalogs());
63 ilm 253
                        allCats = new HashSet<String>(allCatsList);
254
                    } finally {
255
                        this.getDS().returnConnection(conn);
256
                    }
257
                    final Set<String> cats = CollectionUtils.inter(namesToRefresh, allCats);
61 ilm 258
                    this.getDBSystemRoot().filterNodes(this, cats);
17 ilm 259
 
61 ilm 260
                    SQLBase.mustContain(this, cats, childrenToRefresh, "bases");
261
                    for (final String base : CollectionUtils.substract(childrenToRefresh, cats)) {
262
                        final CollectionChangeEventCreator c = this.createChildrenCreator();
263
                        final SQLBase existingBase = this.getBases().remove(base);
264
                        this.fireChildrenChanged(c);
265
                        // null if it was never created
266
                        if (existingBase != null)
267
                            existingBase.dropped();
268
                    }
269
                    // delete the saved bases that we could have fetched, but haven't
270
                    // (bases that are not in scope are simply ignored, NOT deleted)
271
                    final DBFileCache cache = this.getFileCache();
272
                    if (cache != null) {
273
                        for (final DBItemFileCache savedBase : cache.getServerCache().getSavedDesc(SQLBase.class)) {
274
                            final String savedBaseName = savedBase.getName();
275
                            if (!cats.contains(savedBaseName) && (namesToRefresh == null || namesToRefresh.contains(savedBaseName)) && this.getDBSystemRoot().createNode(this, savedBaseName)) {
80 ilm 276
                                AccessController.doPrivileged(new PrivilegedAction<Object>() {
277
                                    @Override
278
                                    public Object run() {
279
                                        savedBase.delete();
280
                                        return null;
281
                                    }
282
                                });
61 ilm 283
                            }
17 ilm 284
                        }
285
                    }
286
 
65 ilm 287
                    // fire once all the bases are loaded so that the graph is coherent
67 ilm 288
                    return this.getDBSystemRoot().getGraph().atomicRefresh(new Callable<Map<String, TablesMap>>() {
182 ilm 289
 
65 ilm 290
                        @Override
67 ilm 291
                        public Map<String, TablesMap> call() throws Exception {
292
                            final Map<String, TablesMap> res = new HashMap<String, TablesMap>();
65 ilm 293
                            // add or refresh
294
                            for (final String cat : cats) {
67 ilm 295
                                final TablesMap jdbcTables;
65 ilm 296
                                final SQLBase existing = getBase(cat);
67 ilm 297
                                if (existing != null) {
298
                                    jdbcTables = existing.refresh(tablesToRefresh == null ? null : tablesToRefresh.get(cat), readCache);
299
                                } else {
300
                                    // ignore tablesToRefresh if the base didn't exist (see
301
                                    // SQLBase.assureAllTables())
65 ilm 302
                                    // we already have the datasource, so login/pass aren't used
83 ilm 303
                                    jdbcTables = createBase(cat, null, "", "", DSINIT_ERROR, readCache);
67 ilm 304
                                }
305
                                if (!jdbcTables.isEmpty())
306
                                    res.put(cat, jdbcTables);
65 ilm 307
                            }
67 ilm 308
                            return res;
65 ilm 309
                        }
310
                    });
17 ilm 311
                }
312
            } catch (SQLException e) {
313
                throw new IllegalStateException("could not get children names", e);
63 ilm 314
            } finally {
315
                this.getDBSystemRoot().fireLoading(evt.createFinishingEvent());
17 ilm 316
            }
61 ilm 317
        } else if (!init) {
318
            throw new IllegalArgumentException("Cannot create bases since this server cannot have a connection");
17 ilm 319
        }
67 ilm 320
        return null;
17 ilm 321
    }
322
 
323
    /**
324
     * Copy constructor. The new instance is in the same state <code>s</code> was, when it was
325
     * created (no SQLBase, no default base).
326
     *
327
     * @param s the server to copy from.
328
     */
329
    public SQLServer(SQLServer s) {
65 ilm 330
        this(s.system, s.getName(), null, s.login, s.pass);
17 ilm 331
    }
332
 
333
    // tries to get a ds without any db
61 ilm 334
    private synchronized final SQLDataSource getDS() {
17 ilm 335
        if (!this.dsSet) {
61 ilm 336
            this.checkDropped();
17 ilm 337
            final DBSystemRoot sysRoot = this.getDBSystemRoot();
338
            if (sysRoot == null) {
339
                this.ds = null;
340
            } else {
341
                // should not succeed if pb otherwise with dsSet
342
                // it will never be called again
343
                this.ds = sysRoot.getDataSource();
344
            }
345
            this.dsSet = true;
346
        }
347
        return this.ds;
348
    }
349
 
350
    final String getURL(String base) {
351
        return this.urlTransf.transformChecked(base);
352
    }
353
 
354
    /**
355
     * Retourne la base par défaut.
356
     *
357
     * @return la base par défaut.
358
     * @see #setDefaultBase(String)
359
     */
360
    public SQLBase getBase() {
61 ilm 361
        final String def;
362
        synchronized (this) {
363
            def = this.defaultBase;
364
        }
365
        if (def == null) {
17 ilm 366
            throw new IllegalStateException("default base unset");
367
        }
61 ilm 368
        return this.getBase(def);
17 ilm 369
    }
370
 
61 ilm 371
    public SQLBase getBase(String baseName) {
372
        return this.getBases().get(baseName);
373
    }
374
 
17 ilm 375
    /**
376
     * Return the specified base using default login/pass.
377
     *
378
     * @param baseName the name of base to be returned.
379
     * @return the SQLBase named <i>baseName</i>.
380
     * @see #getBase(String, String, String, IClosure)
381
     */
61 ilm 382
    public SQLBase getOrCreateBase(String baseName) {
17 ilm 383
        return this.getBase(baseName, null, null);
384
    }
385
 
386
    public SQLBase getBase(String baseName, String login, String pass) {
387
        return this.getBase(baseName, login, pass, null);
388
    }
389
 
390
    /**
391
     * Return the specified base using provided login/pass. Does nothing if there's already a base
392
     * with this name.
393
     *
394
     * @param baseName the name of the base.
395
     * @param login the login, <code>null</code> means default.
396
     * @param pass the password, <code>null</code> means default.
397
     * @param dsInit to initialize the datasource before any request (eg setting jdbc properties),
398
     *        <code>null</code> meaning take the server one.
399
     * @return the corresponding base.
400
     */
83 ilm 401
    public SQLBase getBase(String baseName, String login, String pass, IClosure<? super SQLDataSource> dsInit) {
402
        return this.getBase(baseName, null, login, pass, dsInit, true);
65 ilm 403
    }
404
 
83 ilm 405
    public SQLBase getBase(String baseName, final IClosure<? super DBSystemRoot> systemRootInit, String login, String pass, IClosure<? super SQLDataSource> dsInit, boolean readCache) {
67 ilm 406
        if (this.getDBSystemRoot() != null)
65 ilm 407
            throw new IllegalStateException("getBase(name, login, pass) should only be used for systems where SQLBase is DBSystemRoot");
61 ilm 408
        synchronized (this.getTreeMutex()) {
409
            SQLBase base = this.getBase(baseName);
410
            if (base == null) {
83 ilm 411
                this.createBase(baseName, systemRootInit, login, pass, dsInit, readCache);
67 ilm 412
                base = this.getBase(baseName);
61 ilm 413
            }
414
            return base;
17 ilm 415
        }
416
    }
417
 
83 ilm 418
    private final TablesMap createBase(String baseName, IClosure<? super DBSystemRoot> systemRootInit, String login, String pass, IClosure<? super SQLDataSource> dsInit, boolean readCache) {
67 ilm 419
        final DBSystemRoot sysRoot = this.getDBSystemRoot();
420
        if (sysRoot != null && !sysRoot.createNode(this, baseName))
421
            throw new IllegalStateException(baseName + " is filtered, you must add it to rootsToMap");
142 ilm 422
        final SQLBase base = new SQLBase(this, baseName, coalesce(systemRootInit, this.systemRootInit), login == null ? this.login : login, pass == null ? this.pass : pass,
423
                coalesce(dsInit, this.dsInit));
67 ilm 424
        return this.putBase(baseName, base, readCache);
425
    }
426
 
17 ilm 427
    public final DBSystemRoot getSystemRoot(String name) {
83 ilm 428
        return this.getSystemRoot(name, null, null, null, null);
17 ilm 429
    }
430
 
431
    /**
432
     * Return the specified systemRoot using provided login/pass. Does nothing if there's already a
433
     * systemRoot with this name.
434
     *
435
     * @param name name of the system root, NOTE: for some systems the server is the systemRoot so
436
     *        <code>name</code> will be silently ignored.
83 ilm 437
     * @param systemRootInit to initialize the {@link DBSystemRoot} before setting the data source.
17 ilm 438
     * @param login the login, <code>null</code> means default.
439
     * @param pass the password, <code>null</code> means default.
440
     * @param dsInit to initialize the datasource before any request (eg setting jdbc properties),
441
     *        <code>null</code> meaning take the server one.
442
     * @return the corresponding systemRoot.
443
     * @see #isSystemRootCreated(String)
444
     */
83 ilm 445
    public final DBSystemRoot getSystemRoot(String name, final IClosure<? super DBSystemRoot> systemRootInit, String login, String pass, IClosure<? super SQLDataSource> dsInit) {
61 ilm 446
        synchronized (this.getTreeMutex()) {
447
            if (!this.isSystemRootCreated(name)) {
83 ilm 448
                return this.createSystemRoot(name, systemRootInit, login, pass, dsInit);
61 ilm 449
            } else {
450
                final DBSystemRoot res;
451
                final DBSystemRoot sysRoot = this.getDBSystemRoot();
452
                if (sysRoot != null)
453
                    res = sysRoot;
454
                else {
455
                    res = this.getBase(name).getDBSystemRoot();
456
                }
457
                return res;
17 ilm 458
            }
459
        }
460
    }
461
 
83 ilm 462
    private final DBSystemRoot createSystemRoot(String name, IClosure<? super DBSystemRoot> systemRootInit, String login, String pass, IClosure<? super SQLDataSource> dsInit) {
17 ilm 463
        final DBSystemRoot res;
61 ilm 464
        synchronized (this.getTreeMutex()) {
465
            final DBSystemRoot sysRoot = this.getDBSystemRoot();
466
            if (sysRoot != null) {
467
                res = sysRoot;
83 ilm 468
                res.setDS(coalesce(systemRootInit, this.systemRootInit), login == null ? this.login : login, pass == null ? this.pass : pass, coalesce(dsInit, this.dsInit));
61 ilm 469
            } else {
83 ilm 470
                res = this.getBase(name, coalesce(systemRootInit, this.systemRootInit), login, pass, dsInit, true).getDBSystemRoot();
61 ilm 471
            }
17 ilm 472
        }
473
        return res;
474
    }
475
 
476
    /**
477
     * Whether the system root is created and has a datasource.
478
     *
479
     * @param name the system root name.
480
     * @return <code>true</code> if the system root has a datasource.
481
     */
482
    public final boolean isSystemRootCreated(String name) {
61 ilm 483
        synchronized (this.getTreeMutex()) {
484
            final DBSystemRoot sysRoot = this.getDBSystemRoot();
485
            if (sysRoot != null)
486
                return sysRoot.hasDataSource();
487
            else
488
                return this.isCreated(name) && this.getBase(name).getDBSystemRoot().hasDataSource();
489
        }
17 ilm 490
    }
491
 
67 ilm 492
    private TablesMap putBase(String baseName, SQLBase base, boolean readCache) {
61 ilm 493
        assert Thread.holdsLock(getTreeMutex());
17 ilm 494
        final CollectionChangeEventCreator c = this.createChildrenCreator();
495
        this.getBases().put(baseName, base);
67 ilm 496
        final TablesMap res = base.init(readCache);
17 ilm 497
        this.fireChildrenChanged(c);
498
        // if base is null, no new tables (furthermore descendantsChanged() would create our
499
        // children)
500
        if (base != null)
501
            if (this.getDBSystemRoot() != null)
65 ilm 502
                this.getDBSystemRoot().descendantsChanged(this, Collections.singleton(baseName), readCache);
61 ilm 503
        // defaultBase must be null, otherwise the user has already expressed his choice
504
        synchronized (this) {
505
            final boolean setDef = this.defaultBase == null && base != null;
506
            if (setDef) {
507
                this.setDefaultBase(baseName);
508
            }
17 ilm 509
        }
67 ilm 510
        return res;
17 ilm 511
    }
512
 
513
    @Override
61 ilm 514
    public Map<String, SQLBase> getChildrenMap() {
515
        return this.getBases().getImmutable();
17 ilm 516
    }
517
 
518
    /**
519
     * Has the passed base already been created. Useful as when this returns <code>true</code>,
520
     * {@link #getBase(String, String, String, IClosure)} won't do anything but return the already
521
     * created base, in particular the closure won't be used.
522
     *
523
     * @param baseName the name of the base.
524
     * @return <code>true</code> if an instance of SQLBase already exists.
525
     */
526
    public boolean isCreated(String baseName) {
61 ilm 527
        return this.getBase(baseName) != null;
17 ilm 528
    }
529
 
530
    /**
531
     * Met la base par défaut. Note: la première base ajoutée devient automatiquement la base par
532
     * défaut.
533
     *
534
     * @param defaultBase le nom de la base par défaut, can be <code>null</code>.
535
     * @see #getBase()
536
     */
537
    public void setDefaultBase(String defaultBase) {
61 ilm 538
        synchronized (this.getTreeMutex()) {
539
            if (defaultBase != null && !this.contains(defaultBase))
540
                throw new IllegalArgumentException(defaultBase + " unknown");
541
            synchronized (this) {
542
                this.defaultBase = defaultBase;
543
            }
544
        }
17 ilm 545
    }
546
 
547
    public String toString() {
548
        return this.getName();
549
    }
550
 
551
    /**
552
     * Return the name of the system of this server.
553
     *
554
     * @return the name of the system.
555
     * @deprecated use {@link #getSQLSystem()}
556
     */
557
    public final String getSystem() {
558
        return this.getSQLSystem().getJDBCName();
559
    }
560
 
561
    public final SQLSystem getSQLSystem() {
562
        return this.system;
563
    }
564
 
67 ilm 565
    public final synchronized void setID(final String id) {
566
        this.id = id;
567
    }
568
 
569
    // needed since the host doesn't always identify one server (e.g. 127.0.0.1:1234 might be a
570
    // tunnel to different servers)
571
    public final synchronized String getID() {
572
        return this.id;
573
    }
574
 
17 ilm 575
    public final DBFileCache getFileCache() {
576
        return DBFileCache.create(this);
577
    }
578
 
182 ilm 579
    /**
580
     * The host name of this server.
581
     *
582
     * @return the host name, <code>null</code> if not accessed through network.
583
     */
17 ilm 584
    public final String getHostname() {
182 ilm 585
        return this.getHostnameAndPath().get0();
17 ilm 586
    }
182 ilm 587
 
588
    public final List2<String> getHostnameAndPath() {
589
        return this.getSQLSystem().getHostnameAndPath(this.getName());
590
    }
591
 
592
    public final boolean isPermanent() {
593
        return this.getSQLSystem().isPermanent(this.getName());
594
    }
595
 
596
    /**
597
     * Whether this server runs on the local machine.
598
     *
599
     * @return <code>true</code> if the JVM runs on the same machine than <code>this</code>.
600
     */
601
    protected final boolean isLocalhost() {
602
        // this method cannot be in SQLSyntax since it is used in the constructor of SQLDataSource
603
        // (which is needed by SQLSyntax.create())
604
 
605
        final String host = this.getHostname();
606
        if (host == null)
607
            return true;
608
        final int colonIndex = host.indexOf(':');
609
        final String hostWOPort = colonIndex < 0 ? host : host.substring(0, colonIndex);
610
        return NetUtils.isSelfAddr(hostWOPort);
611
    }
612
 
613
    public final boolean isPersistent() {
614
        return this.getSQLSystem() != SQLSystem.H2 || !this.getName().equals(SQLSystem.H2_IN_MEMORY);
615
    }
17 ilm 616
}