MentaBean

Rev

Rev 176 | Rev 189 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 soliveira 1
/*
22 soliveira 2
 * This program is free software: you can redistribute it and/or modify
3
 * it under the terms of the GNU General Public License as published by
4
 * the Free Software Foundation, either version 3 of the License, or
5
 * (at your option) any later version.
2 soliveira 6
 *
22 soliveira 7
 * This program is distributed in the hope that it will be useful,
8
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 * GNU General Public License for more details.
2 soliveira 11
 *
22 soliveira 12
 * You should have received a copy of the GNU General Public License
13
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
2 soliveira 14
 *
22 soliveira 15
 * MentaBean => http://www.mentabean.org
16
 * Author: Sergio Oliveira Jr. (sergio.oliveira.jr@gmail.com)
2 soliveira 17
 */
18
package org.mentabean;
19
 
20
import java.util.Iterator;
61 soliveira 21
import java.util.LinkedHashMap;
22
import java.util.Map;
2 soliveira 23
 
149 erico 24
import org.mentabean.event.TriggerDispatcher;
25
import org.mentabean.event.TriggerListener;
2 soliveira 26
import org.mentabean.type.AutoIncrementType;
27
import org.mentabean.type.SequenceType;
118 soliveira 28
import org.mentabean.util.PropertiesProxy;
2 soliveira 29
 
8 soliveira 30
/**
22 soliveira 31
 * A class representing a bean configuration, like table name, primary keys and fields in the database.
8 soliveira 32
 *
33
 * @author sergio.oliveira.jr@gmail.com
34
 */
2 soliveira 35
public class BeanConfig {
36
 
61 soliveira 37
        private final Map<String, DBField> fieldList = new LinkedHashMap<String, DBField>();
2 soliveira 38
 
61 soliveira 39
        private final Map<String, DBField> pkList = new LinkedHashMap<String, DBField>();
69 soliveira 40
 
169 erico 41
        private final Map<String, Class<? extends Object>> abstractInstances = new LinkedHashMap<String, Class<? extends Object>>();
42
 
2 soliveira 43
        private final Class<? extends Object> beanClass;
44
 
45
        private final String tableName;
46
 
47
        private DBField sequence = null;
74 soliveira 48
 
49
        private String sequenceName = null;
2 soliveira 50
 
51
        private DBField autoincrement = null;
149 erico 52
 
53
        private TriggerDispatcher dispatcher = new TriggerDispatcher();
2 soliveira 54
 
8 soliveira 55
        /**
56
         * Creates a configuration for a bean represented by the given class.
57
         *
11 soliveira 58
         * @param beanClass
59
         *            The bean klass
60
         * @param tableName
61
         *            The database table where the bean properties will be stored.
8 soliveira 62
         */
2 soliveira 63
        public BeanConfig(final Class<? extends Object> beanClass, final String tableName) {
64
 
65
                this.beanClass = beanClass;
66
 
67
                this.tableName = tableName;
68
        }
69
 
8 soliveira 70
        /**
71
         * Return the table name where the bean properties are stored.
72
         *
73
         * @return The database table name.
74
         */
2 soliveira 75
        public String getTableName() {
76
 
77
                return tableName;
78
        }
79
 
8 soliveira 80
        /**
81
         * Return the bean class.
82
         *
83
         * @return The bean class.
84
         */
2 soliveira 85
        public Class<? extends Object> getBeanClass() {
86
 
87
                return beanClass;
88
        }
89
 
69 soliveira 90
        /**
91
         * Add the sequence name *in the database* that will be used for this field.
92
         *
93
         * NOTE: A field of type SEQUENCE must have been defined before or an IllegalStateException is thrown.
94
         *
95
         * @param seqNameInDb the name of the sequence in the database
96
         * @return this bean config
97
         */
74 soliveira 98
        public BeanConfig addSequenceName(String seqNameInDb) {
69 soliveira 99
 
74 soliveira 100
                if (sequence == null) {
101
                        throw new IllegalStateException("There is no sequence field defined!");
69 soliveira 102
                }
103
 
74 soliveira 104
                sequenceName = seqNameInDb;
69 soliveira 105
                return this;
106
        }
107
 
108
        /**
109
         * Alias for method addSequence
110
         *
111
         * @param seqNameInDb
73 soliveira 112
         * @return this bean config
69 soliveira 113
         */
74 soliveira 114
        public BeanConfig seq(String seqNameInDb) {
115
                return addSequenceName(seqNameInDb);
69 soliveira 116
        }
11 soliveira 117
 
69 soliveira 118
        /**
74 soliveira 119
         * Returns the name of the sequence in the database.
69 soliveira 120
         *
121
         * NOTE: The name returned is the name of the sequence in the database.
122
         *
188 soliveira 123
         * @return the name of the sequence in the database
69 soliveira 124
         */
74 soliveira 125
        public String getSequenceName() {
126
                return sequenceName;
69 soliveira 127
        }
128
 
112 soliveira 129
        public BeanConfig remove(final String name) {
118 soliveira 130
 
131
                if (name == null) {
132
                        return remove((Object) null);
133
                }
134
 
112 soliveira 135
                fieldList.remove(name);
136
                pkList.remove(name);
137
                return this;
138
        }
139
 
118 soliveira 140
        public BeanConfig remove(Object propValueFromGetter) {
122 soliveira 141
                return remove(PropertiesProxy.getPropertyName());
118 soliveira 142
        }
143
 
34 soliveira 144
        private BeanConfig addField(final String name, final String dbName, final DBType<? extends Object> type, final boolean isPK) {
11 soliveira 145
 
8 soliveira 146
                if (!isPK) {
11 soliveira 147
 
8 soliveira 148
                        if (type instanceof SequenceType) {
149
                                throw new IllegalStateException("A sequence type can only be a primary key!");
150
                        }
11 soliveira 151
 
8 soliveira 152
                        if (type instanceof AutoIncrementType) {
153
                                throw new IllegalStateException("A auto-increment type can only be a primary key!");
154
                        }
155
                }
2 soliveira 156
 
8 soliveira 157
                final DBField f = new DBField(name, dbName, type, isPK);
2 soliveira 158
 
61 soliveira 159
                fieldList.remove(name); // just in case we are re-adding it...
2 soliveira 160
 
61 soliveira 161
                fieldList.put(name, f);
169 erico 162
 
2 soliveira 163
                if (isPK) {
164
 
61 soliveira 165
                        pkList.remove(name); // just in case we are re-adding it...
2 soliveira 166
 
61 soliveira 167
                        pkList.put(name, f);
168
 
8 soliveira 169
                        if (type instanceof SequenceType) {
11 soliveira 170
 
8 soliveira 171
                                if (sequence != null) {
172
                                        throw new IllegalStateException("A bean can have only one sequence field!");
173
                                }
2 soliveira 174
 
175
                                sequence = f;
176
 
8 soliveira 177
                        } else if (type instanceof AutoIncrementType) {
2 soliveira 178
 
8 soliveira 179
                                if (autoincrement != null) {
180
                                        throw new IllegalStateException("A bean can have only one auto-increment field!");
181
                                }
11 soliveira 182
 
2 soliveira 183
                                autoincrement = f;
184
                        }
185
                }
186
 
187
                return this;
188
        }
167 soliveira 189
 
190
        public DBField getField(String name) {
191
 
192
                return fieldList.get(name);
193
        }
2 soliveira 194
 
8 soliveira 195
        /**
196
         * Return an auto-increment field, if one was configured for this bean.
197
         *
22 soliveira 198
         * Note: A bean can have only one auto-increment field configured for this bean. Attempting to configure more than one will throw an exception.
8 soliveira 199
         *
22 soliveira 200
         * @return the auto-increment field configured for this bean or null if it was not defined
8 soliveira 201
         */
2 soliveira 202
        public DBField getAutoIncrementField() {
203
 
204
                return autoincrement;
205
        }
206
 
8 soliveira 207
        /**
208
         * Return a sequence field, if one was configured for this bean.
209
         *
22 soliveira 210
         * Note: A bean can have only one sequence field configured for this bean. Attempting to configure more than one will throw an exception.
8 soliveira 211
         *
22 soliveira 212
         * @return the sequence field configured for this bean or null if it was not defined
8 soliveira 213
         */
2 soliveira 214
        public DBField getSequenceField() {
215
 
216
                return sequence;
217
        }
11 soliveira 218
 
8 soliveira 219
        /**
22 soliveira 220
         * Add a database field for the given property with the given database type. It assumes that the property name is the SAME as the database column name. If they are different, use the other addField method.
8 soliveira 221
         *
11 soliveira 222
         * @param name
223
         *            The bean property name (same as the database column name)
224
         * @param type
225
         *            The database type
8 soliveira 226
         * @return This BeanConfig (Fluent API)
227
         */
34 soliveira 228
        public BeanConfig field(final String name, final DBType<? extends Object> type) {
2 soliveira 229
 
118 soliveira 230
                if (name == null) {
231
                        return field((Object) null, type);
232
                }
233
 
8 soliveira 234
                return addField(name, name, type, false);
2 soliveira 235
        }
118 soliveira 236
 
237
        public BeanConfig field(Object propValueFromGetter, final DBType<? extends Object> type) {
238
 
122 soliveira 239
                return field(PropertiesProxy.getPropertyName(), type);
118 soliveira 240
        }
2 soliveira 241
 
8 soliveira 242
        /**
243
         * Add a database field for the given property with the given database type.
244
         *
11 soliveira 245
         * @param name
246
         *            The bean property name
247
         * @param dbName
248
         *            The name of the database column holding this property
249
         * @param type
250
         *            The database type
8 soliveira 251
         * @return This BeanConfig (Fluent API)
252
         */
34 soliveira 253
        public BeanConfig field(final String name, final String dbName, final DBType<? extends Object> type) {
118 soliveira 254
 
255
                if (name == null) {
256
                        return field((Object) null, dbName, type);
257
                }
2 soliveira 258
 
8 soliveira 259
                return addField(name, dbName, type, false);
2 soliveira 260
        }
118 soliveira 261
 
262
        public BeanConfig field(Object propValueFromGetter, String dbName, final DBType<? extends Object> type) {
263
 
122 soliveira 264
                return field(PropertiesProxy.getPropertyName(), dbName, type);
118 soliveira 265
        }
2 soliveira 266
 
8 soliveira 267
        /**
22 soliveira 268
         * Add a bean property that is the primary key in the database. The column name is the same as the property bean name. If they are different use the other pk method. All beans must have a primary key and you can call this method multiple times to support composite primary keys.
8 soliveira 269
         *
11 soliveira 270
         * @param name
271
         *            The bean property name
272
         * @param type
273
         *            The database type
8 soliveira 274
         * @return This BeanConfig (Fluent API)
275
         */
34 soliveira 276
        public BeanConfig pk(final String name, final DBType<? extends Object> type) {
118 soliveira 277
 
278
                if (name == null) {
279
                        return pk((Object) null, type);
280
                }
2 soliveira 281
 
8 soliveira 282
                return addField(name, name, type, true);
2 soliveira 283
        }
118 soliveira 284
 
285
        public BeanConfig pk(Object propValueFromGetter, final DBType<? extends Object> type) {
286
 
122 soliveira 287
                return pk(PropertiesProxy.getPropertyName(), type);
118 soliveira 288
        }
2 soliveira 289
 
8 soliveira 290
        /**
22 soliveira 291
         * Add a property that is the primary key in the database. All beans must have a primary key and you can call this method multiple times to support composite primary keys.
8 soliveira 292
         *
11 soliveira 293
         * @param name
294
         *            The bean property name
295
         * @param dbName
296
         *            The name of the database column holding this property
297
         * @param type
298
         *            The database type
8 soliveira 299
         * @return This BeanConfig (Fluent API)
300
         */
34 soliveira 301
        public BeanConfig pk(final String name, final String dbName, final DBType<? extends Object> type) {
118 soliveira 302
 
303
                if (name == null) {
304
                        return pk((Object) null, dbName, type);
305
                }
2 soliveira 306
 
8 soliveira 307
                return addField(name, dbName, type, true);
2 soliveira 308
        }
118 soliveira 309
 
310
        public BeanConfig pk(Object propValueFromGetter, String dbName, final DBType<? extends Object> type) {
311
 
122 soliveira 312
                return pk(PropertiesProxy.getPropertyName(), dbName, type);
118 soliveira 313
        }
2 soliveira 314
 
8 soliveira 315
        /**
316
         * Return the number of fields configured for this bean. It includes the PK.
317
         *
318
         * @return The number of fields configured for this bean.
319
         */
2 soliveira 320
        public int getNumberOfFields() {
321
 
322
                return fieldList.size();
323
        }
324
 
61 soliveira 325
        public int getNumberOfPKs() {
326
 
327
                return pkList.size();
328
        }
329
 
2 soliveira 330
        @Override
331
        public String toString() {
332
 
333
                final StringBuilder sb = new StringBuilder(64);
334
 
176 soliveira 335
                sb.append("BeanConfig: ").append(beanClass.getSimpleName()).append(" tableName=").append(tableName);
2 soliveira 336
 
337
                return sb.toString();
338
        }
339
 
8 soliveira 340
        /**
341
         * Return all DBFields configured for this bean. It includes the PK as well.
11 soliveira 342
         *
13 soliveira 343
         * @return An Iterator with all DBFields configured for this bean.
8 soliveira 344
         */
2 soliveira 345
        public Iterator<DBField> fields() {
346
 
61 soliveira 347
                return fieldList.values().iterator();
2 soliveira 348
        }
349
 
8 soliveira 350
        /**
351
         * Check whether the primary key was defined.
352
         *
353
         * @return true if a primary key was defined.
354
         */
2 soliveira 355
        public boolean hasPK() {
356
 
357
                return !pkList.isEmpty();
358
        }
359
 
8 soliveira 360
        /**
361
         * Return an iterator with the DBFields for the PK configured for this bean.
362
         *
22 soliveira 363
         * Note: A bean can have more than one property as its primary key, in that case it has a composite primary key.
8 soliveira 364
         *
365
         * @return An iterator with the DBFields for the PK.
366
         */
2 soliveira 367
        public Iterator<DBField> pks() {
368
 
61 soliveira 369
                return pkList.values().iterator();
2 soliveira 370
        }
149 erico 371
 
372
        public BeanConfig trigger(TriggerListener trigger) {
373
 
374
                dispatcher.addTrigger(trigger);
375
 
376
                return this;
377
        }
378
 
379
        public BeanConfig remove(TriggerListener trigger) {
380
 
381
                dispatcher.removeTrigger(trigger);
382
 
383
                return this;
384
        }
385
 
386
        public TriggerDispatcher getDispatcher() {
387
                return dispatcher;
388
        }
389
 
169 erico 390
        /**
391
         * Configures a class that should be used instead of property type to create instances
392
         * through {@link Class#newInstance()} method. It's useful when working with abstract objects
393
         * @param abstractProperty - The property name
394
         * @param clazz - The concrete class
395
         * @return this
396
         */
397
        public BeanConfig abstractInstance(String abstractProperty, Class<? extends Object> clazz) {
398
 
399
                if (abstractProperty == null) {
400
                        return abstractInstance((Object) abstractProperty, clazz);
401
                }
402
 
403
                abstractInstances.put(abstractProperty, clazz);
404
 
405
                return this;
406
 
407
        }      
408
 
409
        /**
410
         * Configures a class that should be used instead of property type to create instances
411
         * through {@link Class#newInstance()} method. It's useful when working with abstract objects
412
         * @param abstractProperty - The property name (through proxy)
413
         * @param clazz - The concrete class
414
         * @return this
415
         */
416
        public <E> BeanConfig abstractInstance(E abstractProperty, Class<? extends E> clazz) {
417
 
418
                return abstractInstance(PropertiesProxy.getPropertyName(), clazz);
419
 
420
        }
421
 
422
        public Class<? extends Object> getAbstractProperty(String key) {
423
 
424
                return abstractInstances.get(key);
425
        }
426
 
2 soliveira 427
}