OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 144 | 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
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
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
 package org.openconcerto.sql.request;
15
 
16
import org.openconcerto.sql.Log;
57 ilm 17
import org.openconcerto.sql.element.SQLElement;
17 ilm 18
import org.openconcerto.sql.element.SQLElementDirectory;
57 ilm 19
import org.openconcerto.sql.element.SQLElementDirectory.DirectoryListener;
156 ilm 20
import org.openconcerto.sql.element.SQLElementNamesFromXML;
17 ilm 21
import org.openconcerto.sql.model.DBRoot;
22
import org.openconcerto.sql.model.SQLField;
57 ilm 23
import org.openconcerto.sql.model.SQLRow;
24
import org.openconcerto.sql.model.SQLRowListRSH;
25
import org.openconcerto.sql.model.SQLRowValues;
26
import org.openconcerto.sql.model.SQLSchema;
27
import org.openconcerto.sql.model.SQLSelect;
28
import org.openconcerto.sql.model.SQLSyntax;
17 ilm 29
import org.openconcerto.sql.model.SQLTable;
57 ilm 30
import org.openconcerto.sql.model.Where;
73 ilm 31
import org.openconcerto.sql.model.graph.SQLKey;
57 ilm 32
import org.openconcerto.sql.utils.SQLCreateTable;
33
import org.openconcerto.sql.utils.SQLUtils;
34
import org.openconcerto.sql.utils.SQLUtils.SQLFactory;
17 ilm 35
import org.openconcerto.utils.CollectionUtils;
73 ilm 36
import org.openconcerto.utils.StringUtils;
80 ilm 37
import org.openconcerto.utils.Tuple2;
156 ilm 38
import org.openconcerto.utils.i18n.Phrase;
17 ilm 39
 
40
import java.io.File;
41
import java.io.FileInputStream;
42
import java.io.IOException;
43
import java.io.InputStream;
57 ilm 44
import java.sql.SQLException;
45
import java.util.Arrays;
46
import java.util.Collections;
17 ilm 47
import java.util.HashMap;
57 ilm 48
import java.util.HashSet;
49
import java.util.Iterator;
50
import java.util.LinkedList;
17 ilm 51
import java.util.List;
52
import java.util.Map;
156 ilm 53
import java.util.Map.Entry;
57 ilm 54
import java.util.Set;
55
import java.util.prefs.Preferences;
17 ilm 56
 
132 ilm 57
import org.jdom2.Document;
58
import org.jdom2.Element;
59
import org.jdom2.JDOMException;
60
import org.jdom2.input.SAXBuilder;
17 ilm 61
 
142 ilm 62
import net.jcip.annotations.GuardedBy;
63
import net.jcip.annotations.ThreadSafe;
64
 
17 ilm 65
/**
66
 * Class to obtain a RowItemDesc from a table and a name.
67
 *
68
 * @author ilm 22 nov. 2004
69
 * @see #getDescFor(SQLTable, String)
70
 */
83 ilm 71
@ThreadSafe
17 ilm 72
public class SQLFieldTranslator {
73
 
73 ilm 74
    // OK since RowItemDesc is immutable
80 ilm 75
    /**
76
     * Instance representing "no description".
77
     */
73 ilm 78
    public static final RowItemDesc NULL_DESC = new RowItemDesc(null, null);
17 ilm 79
 
57 ilm 80
    private static final String METADATA_TABLENAME = SQLSchema.FWK_TABLENAME_PREFIX + "RIV_METADATA";
80 ilm 81
 
82
    /**
83
     * Use the code and not the table name, since the same table might be used differently at
84
     * different times (e.g. dropped then recreated some time later with a different purpose). Or
85
     * conversely, a table might get renamed.
86
     */
57 ilm 87
    private static final String ELEM_FIELDNAME = "ELEMENT_CODE";
88
    private static final String COMP_FIELDNAME = "COMPONENT_CODE";
89
    private static final String ITEM_FIELDNAME = "ITEM";
90
 
91
    private static final String DOC_FIELDNAME = "DOCUMENTATION";
92
    private static final String COL_TITLE_FIELDNAME = "COLUMN_TITLE";
93
    private static final String LABEL_FIELDNAME = "LABEL";
94
 
95
    private static final String CORE_VARIANT = "CORE";
96
    private static final String DB_VARIANT = "DB";
97
 
98
    static public SQLTable getMetaTable(final DBRoot root) throws SQLException {
99
        if (!root.contains(METADATA_TABLENAME)) {
100
            final SQLCreateTable createValueT = new SQLCreateTable(root, METADATA_TABLENAME);
101
            createValueT.setPlain(true);
102
            createValueT.addColumn(SQLSyntax.ID_NAME, createValueT.getSyntax().getPrimaryIDDefinition());
103
            final String nullableVarChar = "varchar(" + Preferences.MAX_KEY_LENGTH + ")";
104
            createValueT.addColumn(ELEM_FIELDNAME, nullableVarChar);
105
            createValueT.addColumn(COMP_FIELDNAME, nullableVarChar);
106
            createValueT.addColumn(ITEM_FIELDNAME, nullableVarChar + " NOT NULL");
107
            createValueT.addUniqueConstraint("uniq", Arrays.asList(ELEM_FIELDNAME, COMP_FIELDNAME, ITEM_FIELDNAME));
108
            createValueT.addVarCharColumn(LABEL_FIELDNAME, 256);
109
            createValueT.addVarCharColumn(COL_TITLE_FIELDNAME, 256);
83 ilm 110
            createValueT.addVarCharColumn(DOC_FIELDNAME, Preferences.MAX_VALUE_LENGTH, true);
57 ilm 111
            root.createTable(createValueT);
112
        }
113
        return root.getTable(METADATA_TABLENAME);
114
    }
115
 
73 ilm 116
    public static RowItemDesc getDefaultDesc(SQLField f) {
117
        String name = f.getName(), label = null;
118
        if (f.isPrimaryKey())
119
            label = "ID";
120
        else if (f.getTable().getForeignKeys().contains(f))
121
            name = name.startsWith(SQLKey.PREFIX) ? name.substring(SQLKey.PREFIX.length()) : name;
122
        if (label == null)
123
            label = cleanupName(name);
124
        return new RowItemDesc(label, label);
125
    }
126
 
127
    private static String cleanupName(final String name) {
128
        return StringUtils.firstUpThenLow(name).replace('_', ' ');
129
    }
130
 
131
    public static RowItemDesc getDefaultDesc(SQLTable t, final String name) {
132
        if (t.contains(name))
133
            return getDefaultDesc(t.getField(name));
134
 
135
        final String label = cleanupName(name);
136
        return new RowItemDesc(label, label);
137
    }
138
 
17 ilm 139
    // Instance members
140
 
57 ilm 141
    // { SQLTable -> { compCode, variant, item -> RowItemDesc }}
83 ilm 142
    @GuardedBy("this")
57 ilm 143
    private final Map<SQLTable, Map<List<String>, RowItemDesc>> translation;
156 ilm 144
    // { element code -> { variant -> name }}
145
    @GuardedBy("this")
146
    private final Map<String, Map<String, Phrase>> elementNames;
57 ilm 147
    private final SQLTable table;
17 ilm 148
    private final SQLElementDirectory dir;
83 ilm 149
    @GuardedBy("this")
57 ilm 150
    private final Set<String> unknownCodes;
17 ilm 151
 
152
    {
57 ilm 153
        this.translation = new HashMap<SQLTable, Map<List<String>, RowItemDesc>>();
156 ilm 154
        this.elementNames = new HashMap<>();
57 ilm 155
        this.unknownCodes = new HashSet<String>();
17 ilm 156
    }
157
 
158
    /**
159
     * Create a new instance.
160
     *
161
     * @param root the default root for tables.
142 ilm 162
     * @param dir the directory where to look for tables not in <code>root</code>.
17 ilm 163
     */
156 ilm 164
    public SQLFieldTranslator(DBRoot root, SQLElementDirectory dir) {
57 ilm 165
        try {
166
            this.table = getMetaTable(root);
167
        } catch (SQLException e) {
168
            throw new IllegalStateException("Couldn't get the meta table", e);
169
        }
17 ilm 170
        this.dir = dir;
57 ilm 171
        this.dir.addListener(new DirectoryListener() {
172
            @Override
173
            public void elementRemoved(SQLElement elem) {
174
                // nothing, SQLElement is not required (only needed for code)
175
            }
176
 
177
            @Override
178
            public void elementAdded(SQLElement elem) {
83 ilm 179
                final boolean isUnknown;
180
                synchronized (SQLFieldTranslator.this) {
181
                    isUnknown = SQLFieldTranslator.this.unknownCodes.contains(elem.getCode());
182
                }
183
                if (isUnknown) {
57 ilm 184
                    fetch(Collections.singleton(elem.getCode()));
185
                }
186
            }
187
        });
188
        fetchAndPut(this.table, null);
17 ilm 189
    }
190
 
142 ilm 191
    public final SQLElementDirectory getDirectory() {
192
        return this.dir;
193
    }
194
 
17 ilm 195
    /**
196
     * Add all translations of <code>o</code> to this, note that if a table is present in both this
197
     * and <code>o</code> its translations won't be changed.
198
     *
199
     * @param o another SQLFieldTranslator to add.
200
     */
201
    public void putAll(SQLFieldTranslator o) {
83 ilm 202
        if (o == this)
203
            return;
204
        final int thisHash = System.identityHashCode(this);
205
        final int oHash = System.identityHashCode(o);
206
        final SQLFieldTranslator o1, o2;
207
        if (thisHash < oHash) {
208
            o1 = this;
209
            o2 = o;
210
        } else if (thisHash > oHash) {
211
            o1 = o;
212
            o2 = this;
213
        } else {
214
            throw new IllegalStateException("Hash equal");
215
        }
216
        synchronized (o1) {
217
            synchronized (o2) {
218
                CollectionUtils.addIfNotPresent(this.translation, o.translation);
219
            }
220
        }
17 ilm 221
    }
222
 
156 ilm 223
    public void load(DBRoot b, File file, final SQLElementNamesFromXML elemNames) {
224
        try (final InputStream ins = new FileInputStream(file)) {
225
            this.load(b, ins, elemNames);
226
        } catch (IOException e) {
17 ilm 227
            e.printStackTrace();
228
        }
229
    }
230
 
231
    private static List<Element> getChildren(final Element elem) {
232
        return elem.getChildren();
233
    }
234
 
156 ilm 235
    public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, InputStream inputStream, final SQLElementNamesFromXML elemNames) {
236
        return this.load(b, CORE_VARIANT, inputStream, elemNames);
57 ilm 237
    }
238
 
80 ilm 239
    /**
240
     * Load translations from the passed stream.
241
     *
242
     * @param b the default root for tables.
243
     * @param variant the variant to use.
244
     * @param inputStream the XML.
156 ilm 245
     * @param elemNames how to load element names.
80 ilm 246
     * @return the loaded tables and the names not found (and thus not loaded).
247
     */
156 ilm 248
    public Tuple2<Set<SQLTable>, Set<String>> load(DBRoot b, final String variant, InputStream inputStream, final SQLElementNamesFromXML elemNames) {
17 ilm 249
        if (inputStream == null)
250
            throw new NullPointerException("inputStream is null");
57 ilm 251
        final Set<SQLTable> res = new HashSet<SQLTable>();
80 ilm 252
        final Set<String> notFound = new HashSet<String>();
17 ilm 253
        try {
254
            final Document doc = new SAXBuilder().build(inputStream);
255
            // System.out.println("Base de donnée:"+base);
256
            for (final Element elem : getChildren(doc.getRootElement())) {
257
                final String elemName = elem.getName().toLowerCase();
80 ilm 258
                final DBRoot root;
259
                final List<Element> tableElems;
156 ilm 260
                if (elemName.equals("table") || elemName.equals("element")) {
80 ilm 261
                    root = b;
262
                    tableElems = Collections.singletonList(elem);
263
                } else {
156 ilm 264
                    if (elemName.equals("root")) {
265
                        Log.get().warning("Ignoring deprecated <root> element, use element code to refer to tables outside the default root");
266
                    }
80 ilm 267
                    root = null;
268
                    tableElems = null;
269
                }
270
                if (tableElems != null) {
271
                    for (final Element tableElem : tableElems) {
156 ilm 272
                        final Tuple2<String, SQLTable> t = load(root, variant, tableElem, elemNames, true);
80 ilm 273
                        if (t.get1() == null) {
274
                            notFound.add(t.get0());
275
                        } else {
276
                            res.add(t.get1());
277
                        }
17 ilm 278
                    }
279
                }
280
            }
80 ilm 281
            // load() returns null if no table is found
282
            assert !res.contains(null);
17 ilm 283
        } catch (JDOMException e) {
284
            e.printStackTrace();
285
        } catch (IOException e) {
286
            e.printStackTrace();
287
        }
80 ilm 288
        return Tuple2.create(res, notFound);
17 ilm 289
    }
290
 
156 ilm 291
    private Tuple2<String, SQLTable> load(DBRoot b, final String variant, final Element tableElem, final SQLElementNamesFromXML elemNames, final boolean lenient) {
17 ilm 292
        final String tableName = tableElem.getAttributeValue("name");
156 ilm 293
        String elemCode = tableElem.getAttributeValue("refid");
294
        SQLTable table = null;
295
        // compatibility mode for files without element names
296
        final boolean compatMode = tableElem.getName().toLowerCase().equals("table");
297
        if (compatMode) {
298
            table = this.dir == null || this.dir.getElement(tableName) == null ? b.getTable(tableName) : this.dir.getElement(tableName).getTable();
299
            if (elemCode == null)
300
                elemCode = tableName;
301
        }
302
        if (table == null && this.dir != null && this.dir.getElementForCode(elemCode) != null)
303
            table = this.dir.getElementForCode(elemCode).getTable();
80 ilm 304
        if (table != null) {
57 ilm 305
            for (final Element elem : getChildren(tableElem)) {
306
                final String elemName = elem.getName().toLowerCase();
307
                if (elemName.equals("field")) {
308
                    this.load(table, SQLElement.DEFAULT_COMP_ID, variant, elem);
309
                } else if (elemName.equals("component")) {
310
                    final String compCode = elem.getAttributeValue("code");
311
                    for (final Element fieldElem : getChildren(elem)) {
312
                        this.load(table, compCode, variant, fieldElem);
313
                    }
314
                }
17 ilm 315
            }
156 ilm 316
            try {
317
                if (!compatMode) {
318
                    final Entry<String, Phrase> phrase = elemNames.createPhrase(tableElem);
319
                    if (phrase != null)
320
                        this.putElementName(this.dir.getElement(table), phrase.getValue(), variant);
321
                }
322
            } catch (IOException e) {
323
                throw new IllegalStateException("Couldn't parse phrase for " + table, e);
324
            }
80 ilm 325
        } else if (lenient) {
326
            // allow to supply the union all tables and ignore those that aren't in a given base
327
            Log.get().config("Ignore loading of inexistent table " + tableName);
328
        } else {
329
            throw new IllegalStateException("Table not found : " + tableName);
17 ilm 330
        }
80 ilm 331
        return Tuple2.create(tableName, table);
17 ilm 332
    }
333
 
57 ilm 334
    private void load(final SQLTable table, final String compCode, final String variant, final Element fieldElem) {
335
        final String name = fieldElem.getAttributeValue("name");
336
        final String label = fieldElem.getAttributeValue("label");
337
        final String title = fieldElem.getAttributeValue("titlelabel", label);
338
        final String documentation = fieldElem.getText();
339
        this.setDescFor(table, compCode, variant, name, new RowItemDesc(label, title, documentation));
340
    }
341
 
342
    public final void fetch(final Set<String> codes) {
343
        this.fetchAndPut(this.table, codes);
344
    }
345
 
346
    private List<SQLRow> fetchOnly(final SQLTable table, final Where w) {
83 ilm 347
        return SQLRowListRSH.execute(new SQLSelect().addSelectStar(table).setWhere(w));
57 ilm 348
    }
349
 
350
    private void fetchAndPut(final SQLTable table, final Set<String> codes) {
351
        final Where w;
352
        if (codes == null) {
353
            w = null;
354
            this.removeTranslation((SQLTable) null, null, DB_VARIANT, null);
355
        } else {
356
            w = new Where(table.getField(ELEM_FIELDNAME), codes);
357
            for (final String elementCode : codes)
358
                this.removeTranslation(this.dir.getElementForCode(elementCode).getTable(), null, DB_VARIANT, null);
17 ilm 359
        }
57 ilm 360
        for (final SQLRow r : fetchOnly(table, w)) {
361
            final String elementCode = r.getString(ELEM_FIELDNAME);
83 ilm 362
            // needed since tables can be loaded at any time in SQLElementDirectory
363
            // MAYBE use code as the map key instead of SQLTable
364
            final SQLElement elem = this.dir.getElementForCode(elementCode);
365
            if (elem != null) {
366
                final String componentCode = r.getString(COMP_FIELDNAME);
367
                final String item = r.getString(ITEM_FIELDNAME);
368
                final RowItemDesc desc = new RowItemDesc(r.getString(LABEL_FIELDNAME), r.getString(COL_TITLE_FIELDNAME), r.getString(DOC_FIELDNAME));
369
                synchronized (this) {
57 ilm 370
                    putTranslation(elem.getTable(), componentCode, DB_VARIANT, item, desc);
83 ilm 371
                    this.unknownCodes.remove(elementCode);
372
                }
373
            } else {
374
                synchronized (this) {
57 ilm 375
                    this.unknownCodes.add(elementCode);
376
                }
377
            }
378
        }
17 ilm 379
    }
380
 
83 ilm 381
    private synchronized final Map<List<String>, RowItemDesc> getMap(final SQLTable t) {
57 ilm 382
        Map<List<String>, RowItemDesc> elemMap = this.translation.get(t);
383
        if (elemMap == null) {
384
            elemMap = new HashMap<List<String>, RowItemDesc>();
385
            this.translation.put(t, elemMap);
386
        }
387
        return elemMap;
17 ilm 388
    }
389
 
83 ilm 390
    private synchronized final void putTranslation(SQLTable t, String compCode, String variant, String item, RowItemDesc desc) {
57 ilm 391
        if (t == null)
392
            throw new IllegalArgumentException("Table cannot be null");
393
        // needed by remove()
394
        if (compCode == null || variant == null || item == null)
395
            throw new IllegalArgumentException("Values cannot be null");
396
        this.getMap(t).put(Arrays.asList(compCode, variant, item), desc);
17 ilm 397
    }
398
 
83 ilm 399
    private synchronized final void removeTranslation(SQLTable t, String compCode, String variant, String name) {
57 ilm 400
        // null means match everything, OK since we test in putTranslation() that we don't contain
401
        // null values
402
        if (t == null) {
403
            for (final Map<List<String>, RowItemDesc> m : this.translation.values()) {
404
                this.removeTranslation(m, compCode, variant, name);
405
            }
406
        } else {
407
            this.removeTranslation(this.translation.get(t), compCode, variant, name);
408
        }
409
    }
410
 
83 ilm 411
    private synchronized void removeTranslation(Map<List<String>, RowItemDesc> m, String compCode, String variant, String name) {
57 ilm 412
        if (m == null)
413
            return;
414
 
415
        if (compCode == null && variant == null && name == null) {
416
            m.clear();
417
        } else if (compCode != null && variant != null && name != null) {
418
            m.remove(Arrays.asList(compCode, variant, name));
419
        } else {
420
            final Iterator<List<String>> iter = m.keySet().iterator();
421
            while (iter.hasNext()) {
422
                final List<String> l = iter.next();
423
                if ((compCode == null || compCode.equals(l.get(0))) && (variant == null || variant.equals(l.get(1))) && (name == null || name.equals(l.get(2))))
424
                    iter.remove();
425
            }
426
        }
427
    }
428
 
83 ilm 429
    private synchronized final RowItemDesc getTranslation(SQLTable t, String compCode, String variant, String item) {
57 ilm 430
        return this.getMap(t).get(Arrays.asList(compCode, variant, item));
431
    }
432
 
433
    private final RowItemDesc getTranslation(SQLTable t, String compCodeArg, List<String> variants, String name) {
434
        final LinkedList<String> ll = new LinkedList<String>(variants);
435
        ll.addFirst(DB_VARIANT);
436
        ll.addLast(CORE_VARIANT);
437
 
438
        final String[] compCodes;
439
        if (compCodeArg == SQLElement.DEFAULT_COMP_ID)
440
            compCodes = new String[] { SQLElement.DEFAULT_COMP_ID };
441
        else
442
            compCodes = new String[] { compCodeArg, SQLElement.DEFAULT_COMP_ID };
443
        for (final String compCode : compCodes) {
444
            for (final String variant : ll) {
445
                final RowItemDesc labeledField = this.getTranslation(t, compCode, variant, name);
446
                if (labeledField != null)
447
                    return labeledField;
448
            }
449
        }
450
        return null;
451
    }
452
 
17 ilm 453
    public RowItemDesc getDescFor(SQLTable t, String name) {
57 ilm 454
        return getDescFor(t, SQLElement.DEFAULT_COMP_ID, name);
455
    }
456
 
80 ilm 457
    /**
458
     * Find the description for the passed item. This method will search for an SQLElement for
459
     * <code>t</code> to get its {@link SQLElement#getMDPath() variants path}.
460
     *
461
     * @param t the table.
462
     * @param compCode the component code.
463
     * @param name the item name.
464
     * @return the first description that matches the parameters, never <code>null</code> but
465
     *         {@link #NULL_DESC}.
466
     * @see #getDescFor(SQLTable, String, List, String)
467
     */
57 ilm 468
    public RowItemDesc getDescFor(SQLTable t, String compCode, String name) {
73 ilm 469
        final SQLElement element = this.dir == null ? null : this.dir.getElement(t);
470
        final List<String> variants = element == null ? Collections.<String> emptyList() : element.getMDPath();
471
        return getDescFor(t, compCode, variants, name);
57 ilm 472
    }
473
 
474
    public RowItemDesc getDescFor(final String elementCode, String compCode, String name) {
73 ilm 475
        return this.getDescFor(elementCode, compCode, null, name);
57 ilm 476
    }
477
 
478
    public RowItemDesc getDescFor(final String elementCode, String compCode, List<String> variants, String name) {
73 ilm 479
        final SQLElement elem = this.dir.getElementForCode(elementCode);
480
        if (variants == null)
481
            variants = elem.getMDPath();
482
        return this.getDescFor(elem.getTable(), compCode, variants, name);
57 ilm 483
    }
484
 
80 ilm 485
    /**
486
     * Find the description for the passed item. This method will try {compCode, variant, item}
487
     * first with the DB variant, then with each passed variant and last with the default variant,
488
     * until one description is found. If none is found, it will retry with the code
489
     * {@link SQLElement#DEFAULT_COMP_ID}. If none is found, it will retry all the above after
490
     * having refreshed its cache from the DB.
491
     *
492
     * @param t the table.
493
     * @param compCodeArg the component code.
494
     * @param variants the variants to search, not <code>null</code> but can be empty.
495
     * @param name the item name.
496
     * @return the first description that matches the parameters, never <code>null</code> but
497
     *         {@link #NULL_DESC}.
498
     */
57 ilm 499
    public RowItemDesc getDescFor(SQLTable t, String compCodeArg, List<String> variants, String name) {
500
        RowItemDesc labeledField = this.getTranslation(t, compCodeArg, variants, name);
501
        // if nothing found, re-fetch from the DB
73 ilm 502
        if (labeledField == null && this.dir.getElement(t) != null) {
57 ilm 503
            this.fetchAndPut(this.table, Collections.singleton(this.dir.getElement(t).getCode()));
504
            labeledField = this.getTranslation(t, compCodeArg, variants, name);
17 ilm 505
        }
57 ilm 506
        if (labeledField == null) {
73 ilm 507
            // we didn't find a requested item
57 ilm 508
            Log.get().info("unknown item " + name + " in " + t);
509
            return NULL_DESC;
510
        } else {
511
            return labeledField;
512
        }
17 ilm 513
    }
514
 
515
    private RowItemDesc getDescFor(SQLField f) {
73 ilm 516
        return this.getDescFor(f.getTable(), f.getName());
17 ilm 517
    }
518
 
519
    public String getLabelFor(SQLField f) {
520
        return this.getDescFor(f).getLabel();
521
    }
522
 
523
    public String getTitleFor(SQLField f) {
524
        return this.getDescFor(f).getTitleLabel();
525
    }
526
 
57 ilm 527
    public final void setDescFor(final SQLTable table, final String componentCode, final String variant, final String name, final RowItemDesc desc) {
528
        if (DB_VARIANT.equals(variant))
529
            throw new IllegalArgumentException("Use storeDescFor()");
530
        putTranslation(table, componentCode, variant, name, desc);
531
    }
532
 
533
    public final void removeDescFor(SQLTable t, String compCode, String variant, String name) {
534
        if (DB_VARIANT.equals(variant))
535
            throw new IllegalArgumentException("Cannot remove DB values, use deleteDescFor()");
536
        this.removeTranslation(t, compCode, variant, name);
537
    }
538
 
539
    public final void storeDescFor(final String elementCode, final String componentCode, final String name, final RowItemDesc desc) throws SQLException {
540
        this.storeDescFor(this.dir.getElementForCode(elementCode).getTable(), componentCode, name, desc);
541
    }
542
 
543
    public final void storeDescFor(final SQLTable table, final String componentCode, final String name, final RowItemDesc desc) throws SQLException {
544
        final String elementCode = this.dir.getElement(table).getCode();
545
        final Map<String, Object> m = new HashMap<String, Object>();
546
        m.put(ELEM_FIELDNAME, elementCode);
547
        m.put(COMP_FIELDNAME, componentCode);
548
        m.put(ITEM_FIELDNAME, name);
549
        final SQLTable mdT = this.table;
550
        SQLUtils.executeAtomic(this.table.getDBSystemRoot().getDataSource(), new SQLFactory<Object>() {
551
            @Override
552
            public Object create() throws SQLException {
553
                final List<SQLRow> existing = fetchOnly(mdT, Where.and(mdT, m));
554
                assert existing.size() <= 1 : "Unique constraint failed for " + m;
555
                final SQLRowValues vals;
556
                if (existing.size() == 0)
557
                    vals = new SQLRowValues(mdT, m);
558
                else
559
                    vals = existing.get(0).asRowValues();
560
                vals.put(LABEL_FIELDNAME, desc.getLabel());
561
                vals.put(COL_TITLE_FIELDNAME, desc.getTitleLabel());
562
                vals.put(DOC_FIELDNAME, desc.getDocumentation());
563
                vals.commit();
564
                putTranslation(table, componentCode, DB_VARIANT, name, desc);
565
                return null;
566
            }
567
        });
568
    }
569
 
570
    public final void deleteDescFor(final SQLTable elemTable, final String componentCode, final String name) throws SQLException {
571
        Where w = null;
572
        if (elemTable != null)
573
            w = new Where(this.table.getField(ELEM_FIELDNAME), "=", this.dir.getElement(elemTable).getCode()).and(w);
574
        if (componentCode != null)
575
            w = new Where(this.table.getField(COMP_FIELDNAME), "=", componentCode).and(w);
576
        if (name != null)
577
            w = new Where(this.table.getField(ITEM_FIELDNAME), "=", name).and(w);
578
        final String whereString = w == null ? "" : " where " + w.getClause();
579
        try {
580
            this.table.getDBSystemRoot().getDataSource().execute("DELETE FROM " + this.table.getSQLName().quote() + whereString);
581
        } catch (Exception e) {
582
            throw new SQLException(e);
583
        }
584
        this.removeTranslation(elemTable, componentCode, DB_VARIANT, name);
585
    }
156 ilm 586
 
587
    // ** element names
588
 
589
    public final Phrase putElementName(final Class<? extends SQLElement> elemCl, final Phrase phr) {
590
        return this.putElementName(this.getDirectory().getElement(elemCl), phr);
591
    }
592
 
593
    public final Phrase putElementName(final SQLElement elem, final Phrase phr) {
594
        return this.putElementName(elem, phr, CORE_VARIANT);
595
    }
596
 
597
    public synchronized final Phrase putElementName(final SQLElement elem, final Phrase phr, final String variant) {
598
        return this.getElementNameMap(elem, true).put(variant, phr);
599
    }
600
 
601
    private synchronized final Map<String, Phrase> getElementNameMap(final SQLElement elem, final boolean create) {
602
        Map<String, Phrase> elemMap = this.elementNames.get(elem.getCode());
603
        if (elemMap == null && create) {
604
            elemMap = new HashMap<>();
605
            this.elementNames.put(elem.getCode(), elemMap);
606
        }
607
        return elemMap;
608
    }
609
 
610
    public final Phrase getElementName(final SQLElement elem) {
611
        return this.getElementName(elem, elem.getMDPath());
612
    }
613
 
614
    public final Phrase getElementName(final SQLElement elem, final List<String> variantPath) {
615
        for (final String variant : variantPath) {
616
            final Phrase res = this.getElementName(elem, variant);
617
            if (res != null)
618
                return res;
619
        }
620
        return this.getElementName(elem, CORE_VARIANT);
621
    }
622
 
623
    private synchronized final Phrase getElementName(final SQLElement elem, final String variant) {
624
        final Map<String, Phrase> map = this.getElementNameMap(elem, false);
625
        return map == null ? null : map.get(variant);
626
    }
17 ilm 627
}