OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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