OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 26 | Rev 41 | 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;
17
import org.openconcerto.sql.model.DBStructureItemNotFound;
18
import org.openconcerto.sql.model.SQLName;
19
import org.openconcerto.sql.model.SQLTable;
20
import org.openconcerto.utils.CollectionMap;
21
import org.openconcerto.utils.CollectionUtils;
22
import org.openconcerto.utils.cc.ITransformer;
23
 
24
import java.lang.reflect.InvocationTargetException;
19 ilm 25
import java.util.ArrayList;
17 ilm 26
import java.util.Collection;
19 ilm 27
import java.util.Collections;
17 ilm 28
import java.util.HashMap;
29
import java.util.HashSet;
19 ilm 30
import java.util.List;
17 ilm 31
import java.util.Map;
32
import java.util.Set;
33
 
34
/**
35
 * Directory of SQLElement by table.
36
 *
37
 * @author Sylvain CUAZ
38
 */
39
public final class SQLElementDirectory {
40
 
41
    private final Map<SQLTable, SQLElement> elements;
42
    private final CollectionMap<String, SQLTable> tableNames;
27 ilm 43
    private final CollectionMap<String, SQLTable> byCode;
17 ilm 44
    private final CollectionMap<Class<? extends SQLElement>, SQLTable> byClass;
19 ilm 45
    private final List<DirectoryListener> listeners;
17 ilm 46
 
47
    public SQLElementDirectory() {
48
        this.elements = new HashMap<SQLTable, SQLElement>();
49
        // to mimic elements behaviour, if we add twice the same table
50
        // the second one should replace the first one
51
        this.tableNames = new CollectionMap<String, SQLTable>(HashSet.class);
27 ilm 52
        this.byCode = new CollectionMap<String, SQLTable>(HashSet.class);
17 ilm 53
        this.byClass = new CollectionMap<Class<? extends SQLElement>, SQLTable>(HashSet.class);
19 ilm 54
 
55
        this.listeners = new ArrayList<DirectoryListener>();
17 ilm 56
    }
57
 
58
    private static <K> SQLTable getSoleTable(CollectionMap<K, SQLTable> m, K key) throws IllegalArgumentException {
59
        final Collection<SQLTable> res = m.getNonNull(key);
60
        if (res.size() > 1)
61
            throw new IllegalArgumentException(key + " is not unique: " + CollectionUtils.join(res, ",", new ITransformer<SQLTable, SQLName>() {
62
                @Override
63
                public SQLName transformChecked(SQLTable input) {
64
                    return input.getSQLName();
65
                }
66
            }));
67
        return CollectionUtils.getSole(res);
68
    }
69
 
70
    public synchronized final void putAll(SQLElementDirectory o) {
71
        for (final SQLElement elem : o.getElements()) {
72
            if (!this.contains(elem.getTable()))
73
                this.addSQLElement(elem);
74
        }
75
    }
76
 
77
    /**
78
     * Add an element by creating it with the no-arg constructor. If the element cannot find its
79
     * table and thus raise DBStructureItemNotFound, the exception is logged.
80
     *
81
     * @param element the element to add.
82
     */
83
    public final void addSQLElement(final Class<? extends SQLElement> element) {
84
        try {
85
            this.addSQLElement(element.getConstructor().newInstance());
86
        } catch (InvocationTargetException e) {
87
            if (e.getCause() instanceof DBStructureItemNotFound) {
88
                Log.get().config("ignore inexistent tables: " + e.getCause().getLocalizedMessage());
89
                return;
90
            }
91
            throw new IllegalArgumentException("ctor failed", e);
92
        } catch (Exception e) {
93
            throw new IllegalArgumentException("no-arg ctor failed", e);
94
        }
95
    }
96
 
97
    /**
98
     * Adds an already instantiated element.
99
     *
100
     * @param elem the SQLElement to add.
101
     */
102
    public synchronized final void addSQLElement(SQLElement elem) {
103
        this.elements.put(elem.getTable(), elem);
104
        this.tableNames.put(elem.getTable().getName(), elem.getTable());
27 ilm 105
        this.byCode.put(elem.getCode(), elem.getTable());
17 ilm 106
        this.byClass.put(elem.getClass(), elem.getTable());
19 ilm 107
        for (final DirectoryListener dl : this.listeners) {
108
            dl.elementAdded(elem);
109
        }
27 ilm 110
 
17 ilm 111
    }
112
 
113
    public synchronized final boolean contains(SQLTable t) {
114
        return this.elements.containsKey(t);
115
    }
116
 
117
    public synchronized final SQLElement getElement(SQLTable t) {
118
        return this.elements.get(t);
119
    }
120
 
121
    /**
122
     * Search for a table whose name is <code>tableName</code>.
123
     *
124
     * @param tableName a table name, e.g. "ADRESSE".
125
     * @return the corresponding SQLElement, or <code>null</code> if there is no table named
126
     *         <code>tableName</code>.
127
     * @throws IllegalArgumentException if more than one table match.
128
     */
19 ilm 129
    public synchronized final SQLElement getElement(String tableName) {
17 ilm 130
        return this.getElement(getSoleTable(this.tableNames, tableName));
131
    }
132
 
133
    /**
134
     * Search for an SQLElement whose class is <code>clazz</code>.
135
     *
136
     * @param <S> type of SQLElement
137
     * @param clazz the class.
138
     * @return the corresponding SQLElement, or <code>null</code> if none can be found.
139
     * @throws IllegalArgumentException if there's more than one match.
140
     */
19 ilm 141
    public synchronized final <S extends SQLElement> S getElement(Class<S> clazz) {
17 ilm 142
        return clazz.cast(this.getElement(getSoleTable(this.byClass, clazz)));
143
    }
144
 
27 ilm 145
    public synchronized final SQLElement getElementForCode(String code) {
146
        return this.getElement(getSoleTable(this.byCode, code));
147
    }
148
 
17 ilm 149
    public synchronized final Set<SQLTable> getTables() {
19 ilm 150
        return this.getElementsMap().keySet();
17 ilm 151
    }
152
 
153
    public synchronized final Collection<SQLElement> getElements() {
19 ilm 154
        return this.getElementsMap().values();
17 ilm 155
    }
19 ilm 156
 
157
    public final Map<SQLTable, SQLElement> getElementsMap() {
158
        return Collections.unmodifiableMap(this.elements);
159
    }
160
 
161
    /**
162
     * Remove the passed instance. NOTE: this method only remove the specific instance passed, so
163
     * it's a conditional <code>removeSQLElement(elem.getTable())</code>.
164
     *
165
     * @param elem the instance to remove.
166
     * @see #removeSQLElement(SQLTable)
167
     */
168
    public synchronized void removeSQLElement(SQLElement elem) {
169
        if (this.getElement(elem.getTable()) == elem)
170
            this.removeSQLElement(elem.getTable());
171
    }
172
 
173
    /**
174
     * Remove the element for the passed table.
175
     *
176
     * @param t the table to remove.
177
     * @return the removed element, can be <code>null</code>.
178
     */
179
    public synchronized SQLElement removeSQLElement(SQLTable t) {
180
        final SQLElement elem = this.elements.remove(t);
181
        if (elem != null) {
182
            this.tableNames.remove(elem.getTable().getName(), elem.getTable());
27 ilm 183
            this.byCode.remove(elem.getCode(), elem.getTable());
19 ilm 184
            this.byClass.remove(elem.getClass(), elem.getTable());
185
            // MAYBE only reset neighbours.
186
            for (final SQLElement otherElem : this.elements.values())
187
                otherElem.resetRelationships();
188
            for (final DirectoryListener dl : this.listeners) {
189
                dl.elementRemoved(elem);
190
            }
191
        }
192
        return elem;
193
    }
194
 
195
    public synchronized final void addListener(DirectoryListener dl) {
196
        this.listeners.add(dl);
197
    }
198
 
199
    public synchronized final void removeListener(DirectoryListener dl) {
200
        this.listeners.remove(dl);
201
    }
202
 
203
    static public interface DirectoryListener {
204
        void elementAdded(SQLElement elem);
205
 
206
        void elementRemoved(SQLElement elem);
207
    }
17 ilm 208
}