OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 144 | Rev 174 | 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.element;
15
 
16
import org.openconcerto.sql.Log;
132 ilm 17
import org.openconcerto.sql.ShowAs;
18
import org.openconcerto.sql.model.DBRoot;
17 ilm 19
import org.openconcerto.sql.model.DBStructureItemNotFound;
20
import org.openconcerto.sql.model.SQLName;
21
import org.openconcerto.sql.model.SQLTable;
142 ilm 22
import org.openconcerto.sql.request.SQLFieldTranslator;
132 ilm 23
import org.openconcerto.utils.CollectionMap2;
17 ilm 24
import org.openconcerto.utils.CollectionUtils;
83 ilm 25
import org.openconcerto.utils.SetMap;
17 ilm 26
import org.openconcerto.utils.cc.ITransformer;
27
 
28
import java.lang.reflect.InvocationTargetException;
19 ilm 29
import java.util.ArrayList;
17 ilm 30
import java.util.Collection;
19 ilm 31
import java.util.Collections;
17 ilm 32
import java.util.HashMap;
19 ilm 33
import java.util.List;
17 ilm 34
import java.util.Map;
132 ilm 35
import java.util.Map.Entry;
17 ilm 36
import java.util.Set;
37
 
142 ilm 38
import net.jcip.annotations.GuardedBy;
39
 
17 ilm 40
/**
41
 * Directory of SQLElement by table.
42
 *
43
 * @author Sylvain CUAZ
44
 */
45
public final class SQLElementDirectory {
46
 
47
    private final Map<SQLTable, SQLElement> elements;
83 ilm 48
    private final SetMap<String, SQLTable> tableNames;
49
    private final SetMap<String, SQLTable> byCode;
50
    private final SetMap<Class<? extends SQLElement>, SQLTable> byClass;
19 ilm 51
    private final List<DirectoryListener> listeners;
17 ilm 52
 
73 ilm 53
    private String phrasesPkgName;
54
 
142 ilm 55
    @GuardedBy("this")
56
    private SQLFieldTranslator translator;
132 ilm 57
    private final ShowAs showAs;
58
 
17 ilm 59
    public SQLElementDirectory() {
60
        this.elements = new HashMap<SQLTable, SQLElement>();
61
        // to mimic elements behaviour, if we add twice the same table
62
        // the second one should replace the first one
83 ilm 63
        this.tableNames = new SetMap<String, SQLTable>();
64
        this.byCode = new SetMap<String, SQLTable>();
65
        this.byClass = new SetMap<Class<? extends SQLElement>, SQLTable>();
19 ilm 66
 
67
        this.listeners = new ArrayList<DirectoryListener>();
73 ilm 68
 
69
        this.phrasesPkgName = null;
132 ilm 70
 
71
        this.showAs = new ShowAs((DBRoot) null);
17 ilm 72
    }
73
 
144 ilm 74
    public synchronized final void destroy() {
75
        for (final SQLElement elem : this.elements.values()) {
76
            elem.destroy();
77
        }
78
    }
79
 
132 ilm 80
    public final ShowAs getShowAs() {
81
        return this.showAs;
82
    }
83
 
142 ilm 84
    public final synchronized void setTranslator(SQLFieldTranslator translator) {
85
        if (translator.getDirectory() != this)
86
            throw new IllegalArgumentException("Not for this : " + translator);
87
        this.translator = translator;
88
    }
89
 
90
    public synchronized final SQLFieldTranslator getTranslator() {
91
        return this.translator;
92
    }
93
 
83 ilm 94
    private static <K> SQLTable getSoleTable(SetMap<K, SQLTable> m, K key) throws IllegalArgumentException {
17 ilm 95
        final Collection<SQLTable> res = m.getNonNull(key);
96
        if (res.size() > 1)
97
            throw new IllegalArgumentException(key + " is not unique: " + CollectionUtils.join(res, ",", new ITransformer<SQLTable, SQLName>() {
98
                @Override
99
                public SQLName transformChecked(SQLTable input) {
100
                    return input.getSQLName();
101
                }
102
            }));
103
        return CollectionUtils.getSole(res);
104
    }
105
 
106
    public synchronized final void putAll(SQLElementDirectory o) {
107
        for (final SQLElement elem : o.getElements()) {
108
            if (!this.contains(elem.getTable()))
109
                this.addSQLElement(elem);
110
        }
142 ilm 111
        this.translator.putAll(o.getTranslator());
17 ilm 112
    }
113
 
114
    /**
115
     * Add an element by creating it with the no-arg constructor. If the element cannot find its
116
     * table and thus raise DBStructureItemNotFound, the exception is logged.
117
     *
118
     * @param element the element to add.
119
     */
120
    public final void addSQLElement(final Class<? extends SQLElement> element) {
156 ilm 121
        this.addSQLElement(element, null);
122
    }
123
 
124
    public final void addSQLElement(final Class<? extends SQLElement> element, final DBRoot root) {
125
        final SQLElement newInstance;
17 ilm 126
        try {
156 ilm 127
            if (root == null)
128
                newInstance = element.getConstructor().newInstance();
129
            else
130
                newInstance = element.getConstructor(DBRoot.class).newInstance(root);
17 ilm 131
        } catch (InvocationTargetException e) {
132
            if (e.getCause() instanceof DBStructureItemNotFound) {
133
                Log.get().config("ignore inexistent tables: " + e.getCause().getLocalizedMessage());
134
                return;
135
            }
156 ilm 136
            throw new IllegalArgumentException("Constructor failed", e);
17 ilm 137
        } catch (Exception e) {
156 ilm 138
            throw new IllegalArgumentException("Couldn't use constructor", e);
17 ilm 139
        }
156 ilm 140
        this.addSQLElement(newInstance);
17 ilm 141
    }
142
 
143
    /**
144
     * Adds an already instantiated element.
145
     *
146
     * @param elem the SQLElement to add.
80 ilm 147
     * @return the previously added element.
17 ilm 148
     */
80 ilm 149
    public synchronized final SQLElement addSQLElement(SQLElement elem) {
150
        final SQLElement res = this.removeSQLElement(elem.getTable());
17 ilm 151
        this.elements.put(elem.getTable(), elem);
83 ilm 152
        this.tableNames.add(elem.getTable().getName(), elem.getTable());
153
        this.byCode.add(elem.getCode(), elem.getTable());
154
        this.byClass.add(elem.getClass(), elem.getTable());
132 ilm 155
 
156
        final CollectionMap2<String, ? extends List<String>, String> sa = elem.getShowAs();
157
        if (sa != null) {
158
            for (final Entry<String, ? extends List<String>> e : sa.entrySet()) {
159
                try {
160
                    if (e.getKey() == null)
161
                        this.showAs.show(elem.getTable(), e.getValue());
162
                    else
163
                        this.showAs.show(elem.getTable().getField(e.getKey()), e.getValue());
164
                } catch (RuntimeException exn) {
165
                    throw new IllegalStateException("Couldn't add showAs for " + elem + " : " + e, exn);
166
                }
167
            }
168
        }
169
 
19 ilm 170
        for (final DirectoryListener dl : this.listeners) {
171
            dl.elementAdded(elem);
172
        }
73 ilm 173
        elem.setDirectory(this);
80 ilm 174
        return res;
17 ilm 175
    }
176
 
177
    public synchronized final boolean contains(SQLTable t) {
178
        return this.elements.containsKey(t);
179
    }
180
 
181
    public synchronized final SQLElement getElement(SQLTable t) {
182
        return this.elements.get(t);
183
    }
184
 
185
    /**
186
     * Search for a table whose name is <code>tableName</code>.
187
     *
188
     * @param tableName a table name, e.g. "ADRESSE".
189
     * @return the corresponding SQLElement, or <code>null</code> if there is no table named
190
     *         <code>tableName</code>.
191
     * @throws IllegalArgumentException if more than one table match.
192
     */
19 ilm 193
    public synchronized final SQLElement getElement(String tableName) {
17 ilm 194
        return this.getElement(getSoleTable(this.tableNames, tableName));
195
    }
196
 
197
    /**
198
     * Search for an SQLElement whose class is <code>clazz</code>.
199
     *
200
     * @param <S> type of SQLElement
201
     * @param clazz the class.
202
     * @return the corresponding SQLElement, or <code>null</code> if none can be found.
203
     * @throws IllegalArgumentException if there's more than one match.
204
     */
19 ilm 205
    public synchronized final <S extends SQLElement> S getElement(Class<S> clazz) {
17 ilm 206
        return clazz.cast(this.getElement(getSoleTable(this.byClass, clazz)));
207
    }
208
 
27 ilm 209
    public synchronized final SQLElement getElementForCode(String code) {
210
        return this.getElement(getSoleTable(this.byCode, code));
211
    }
212
 
17 ilm 213
    public synchronized final Set<SQLTable> getTables() {
19 ilm 214
        return this.getElementsMap().keySet();
17 ilm 215
    }
216
 
217
    public synchronized final Collection<SQLElement> getElements() {
19 ilm 218
        return this.getElementsMap().values();
17 ilm 219
    }
19 ilm 220
 
221
    public final Map<SQLTable, SQLElement> getElementsMap() {
222
        return Collections.unmodifiableMap(this.elements);
223
    }
224
 
225
    /**
226
     * Remove the passed instance. NOTE: this method only remove the specific instance passed, so
227
     * it's a conditional <code>removeSQLElement(elem.getTable())</code>.
228
     *
229
     * @param elem the instance to remove.
230
     * @see #removeSQLElement(SQLTable)
231
     */
232
    public synchronized void removeSQLElement(SQLElement elem) {
233
        if (this.getElement(elem.getTable()) == elem)
234
            this.removeSQLElement(elem.getTable());
235
    }
236
 
237
    /**
238
     * Remove the element for the passed table.
239
     *
240
     * @param t the table to remove.
241
     * @return the removed element, can be <code>null</code>.
242
     */
243
    public synchronized SQLElement removeSQLElement(SQLTable t) {
244
        final SQLElement elem = this.elements.remove(t);
245
        if (elem != null) {
144 ilm 246
            this.tableNames.removeOne(elem.getTable().getName(), elem.getTable());
247
            this.byCode.removeOne(elem.getCode(), elem.getTable());
248
            this.byClass.removeOne(elem.getClass(), elem.getTable());
19 ilm 249
            // MAYBE only reset neighbours.
250
            for (final SQLElement otherElem : this.elements.values())
251
                otherElem.resetRelationships();
80 ilm 252
            elem.setDirectory(null);
132 ilm 253
            this.showAs.removeTable(elem.getTable());
19 ilm 254
            for (final DirectoryListener dl : this.listeners) {
255
                dl.elementRemoved(elem);
256
            }
257
        }
258
        return elem;
259
    }
260
 
73 ilm 261
    public synchronized final void initL18nPackageName(final String baseName) {
262
        if (this.phrasesPkgName != null)
263
            throw new IllegalStateException("Already initialized : " + this.getL18nPackageName());
264
        this.phrasesPkgName = baseName;
265
    }
266
 
267
    public synchronized final String getL18nPackageName() {
268
        return this.phrasesPkgName;
269
    }
270
 
19 ilm 271
    public synchronized final void addListener(DirectoryListener dl) {
272
        this.listeners.add(dl);
273
    }
274
 
275
    public synchronized final void removeListener(DirectoryListener dl) {
276
        this.listeners.remove(dl);
277
    }
278
 
279
    static public interface DirectoryListener {
280
        void elementAdded(SQLElement elem);
281
 
282
        void elementRemoved(SQLElement elem);
283
    }
17 ilm 284
}