OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

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