001: /*
002: * Created on 22/05/2004
003: *
004: * Swing Components - visit http://sf.net/projects/gfd
005: *
006: * Copyright (C) 2004 Igor Regis da Silva Simões
007: *
008: * This program is free software; you can redistribute it and/or
009: * modify it under the terms of the GNU General Public License
010: * as published by the Free Software Foundation; either version 2
011: * of the License, or (at your option) any later version.
012: *
013: * This program is distributed in the hope that it will be useful,
014: * but WITHOUT ANY WARRANTY; without even the implied warranty of
015: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016: * GNU General Public License for more details.
017: *
018: * You should have received a copy of the GNU General Public License
019: * along with this program; if not, write to the Free Software
020: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
021: *
022: */
023:
024: package br.com.gfpshare.db;
025:
026: import java.lang.reflect.Field;
027: import java.lang.reflect.Modifier;
028: import java.util.ArrayList;
029: import java.util.HashMap;
030: import java.util.Map;
031:
032: /**
033: * @author Igor Regis da Silva Simoes
034: */
035: public abstract class AbstractPersistentObject implements
036: PersistentObject {
037: /**
038: *
039: */
040: private SQLParser sqlParser = null;
041:
042: /**
043: *
044: */
045: protected boolean autoPk = true;
046:
047: /**
048: *
049: */
050: private static HashMap<String, ArrayList<String>> allColumns = new HashMap<String, ArrayList<String>>(
051: 7);
052:
053: /**
054: *
055: */
056: private static HashMap<String, ArrayList<String>> colunas = new HashMap<String, ArrayList<String>>(
057: 7);
058:
059: /**
060: *
061: */
062: private static HashMap<String, ArrayList<String>> pks = new HashMap<String, ArrayList<String>>(
063: 2);
064:
065: /**
066: *
067: */
068: protected boolean[] crescente = null;
069:
070: /**
071: *
072: */
073: private ArrayList<SQLCondition> condicoesExtras = new ArrayList<SQLCondition>();
074:
075: /**
076: *
077: */
078: private String resultadoDesejado = null;
079:
080: /**
081: *
082: */
083: private String dataBase = null;
084:
085: /**
086: * Dados a respeito da atual clausula de sql que será executada por este persistent object
087: */
088: private ParsedPreparedStatement currentStatement = new ParsedPreparedStatement();
089:
090: /**
091: *
092: */
093: public AbstractPersistentObject() {
094: ArrayList<String> allColumns = new ArrayList<String>();
095: allColumns.addAll(getColumnsName());
096: allColumns.addAll(getPkNames());
097:
098: crescente = new boolean[allColumns.size()];
099:
100: for (int i = 0; i < crescente.length; i++) {
101: crescente[i] = true;
102: }
103: if (AbstractPersistentObject.allColumns.get(this .getClass()
104: .getName()) == null)
105: AbstractPersistentObject.allColumns.put(this .getClass()
106: .getName(), allColumns);
107: }
108:
109: /**
110: * @see br.com.gfpshare.db.PersistentObject#getInsertSQL()
111: */
112: public final String getInsertSQL() {
113: if (autoPk)
114: currentStatement = getSqlParser().getInsertSQL(
115: getTableName(), getAsMap(), getColumnsName());
116: else
117: currentStatement = getSqlParser().getInsertSQL(
118: getTableName(),
119: getAsMap(),
120: AbstractPersistentObject.allColumns.get(this
121: .getClass().getName()));
122: return currentStatement.sql;
123: }
124:
125: /**
126: * @see br.com.gfpshare.db.PersistentObject#getUpdateSQL()
127: */
128: public final String getUpdateSQL() {
129: if (autoPk)
130: currentStatement = getSqlParser().getUpdateSQL(
131: getTableName(), getAsMap(), getColumnsName(),
132: getPkNames());
133: else
134: currentStatement = getSqlParser().getUpdateSQL(
135: getTableName(),
136: getAsMap(),
137: AbstractPersistentObject.allColumns.get(this
138: .getClass().getName()), getPkNames());
139: return currentStatement.sql;
140: }
141:
142: /**
143: * @see br.com.gfpshare.db.PersistentObject#getSelectSQL()
144: */
145: public final String getSelectSQL() {
146: condicoesExtras.trimToSize();
147: currentStatement = getSqlParser().getSelectSQL(
148: resultadoDesejado,
149: getTableName(),
150: getAsMap(),
151: AbstractPersistentObject.allColumns.get(this .getClass()
152: .getName()), getOrderBy(), crescente,
153: condicoesExtras);
154: return currentStatement.sql;
155: }
156:
157: /**
158: * @see br.com.gfpshare.db.PersistentObject#getDeleteSQL()
159: */
160: public final String getDeleteSQL() {
161: currentStatement = getSqlParser().getDeleteSQL(
162: getTableName(),
163: getAsMap(),
164: AbstractPersistentObject.allColumns.get(this .getClass()
165: .getName()), condicoesExtras, getPkNames());
166: return currentStatement.sql;
167: }
168:
169: public ArrayList<Object> getParametrosSQL() {
170: ArrayList<Object> retorno = new ArrayList<Object>();
171: for (SQLCondition<Object> condicao : condicoesExtras) {
172: if (condicao.getCondicao() != SQLCondition.Condicao.IS_NULL)
173: retorno.add(condicao.getValor());
174: if (condicao.getCondicao() == SQLCondition.Condicao.BETWEEN)
175: retorno.add(condicao.getValor_2());
176: }
177: retorno.addAll(currentStatement.params);
178: currentStatement = new ParsedPreparedStatement();
179: return retorno;
180: }
181:
182: /**
183: * @see br.com.gfpshare.db.PersistentObject#setOrderBy(java.lang.String[])
184: */
185: public final void setOrderBy(String[] columns) {
186: boolean swap;
187: ArrayList<String> allColumns = AbstractPersistentObject.allColumns
188: .get(getClass().getName());
189:
190: for (int n = columns.length - 1; n >= 0; n--) {
191: for (int i = 0; i < allColumns.size(); i++) {
192: if (allColumns.get(i).toString().equals(columns[n])) {
193: swap = this .crescente[i];
194:
195: for (int j = i; j > 0; j--) {
196: String swap2 = allColumns.get(j - 1);
197: allColumns.set(j - 1, null);
198: allColumns.set(j, swap2);
199: this .crescente[j] = this .crescente[j - 1];
200: }
201:
202: allColumns.set(0, columns[n]);
203: this .crescente[0] = !swap;
204: }
205: }
206:
207: }
208: AbstractPersistentObject.allColumns.put(this .getClass()
209: .getName(), allColumns);
210: }
211:
212: /**
213: * @see br.com.gfpshare.db.PersistentObject#getOrderBy()
214: */
215: public final String[] getOrderBy() {
216: ArrayList<String> allColumns = AbstractPersistentObject.allColumns
217: .get(this .getClass().getName());
218: return allColumns.toArray(new String[allColumns.size()]);
219: }
220:
221: /*
222: * @see br.com.igor.db.PersistentObject#addCondicaoExtra(java.lang.String)
223: */
224: public final void addCondicaoExtra(SQLCondition condicao) {
225: condicoesExtras.add(condicao);
226: }
227:
228: /**
229: * @see br.com.gfpshare.db.PersistentObject#removeCondicaoExtra(java.lang.String)
230: */
231: public final void removeCondicaoExtra(SQLCondition condicao) {
232: condicoesExtras.remove(condicao);
233: }
234:
235: /**
236: * Retorna o parser a ser usado na formulação do sql.
237: * @return SQLParser.
238: */
239: private SQLParser getSqlParser() {
240: if (sqlParser == null)
241: sqlParser = SQLParserFactory.getSQLParserFactory()
242: .getParser(dataBase);
243: return sqlParser;
244: }
245:
246: /**
247: * @see br.com.gfpshare.db.PersistentObject#setDataBase(java.lang.String)
248: */
249: public void setDataBase(String dataBase) {
250: this .dataBase = dataBase;
251: }
252:
253: /**
254: * @see java.lang.Object#toString()
255: */
256: @Override
257: public String toString() {
258: Map objetoMap = getAsMap();
259: Object[] chaves = objetoMap.keySet().toArray();
260:
261: String representacao = getTableName();
262:
263: for (Object chave : chaves)
264: if (objetoMap.get(chave) != null)
265: representacao += ", " + chave + " = "
266: + objetoMap.get(chave);
267:
268: return representacao;
269: }
270:
271: /**
272: * @see br.com.gfpshare.db.PersistentObject#getResultadoDesejado()
273: */
274: public String getResultadoDesejado() {
275: return resultadoDesejado;
276: }
277:
278: /*
279: * @see br.com.igor.db.PersistentObject#setResultadoDesejado(java.lang.String)
280: */
281: public void setResultadoDesejado(String resultadoDesejado) {
282: this .resultadoDesejado = resultadoDesejado;
283: }
284:
285: /**
286: * @see br.com.gfpshare.db.PersistentObject#getColumnsName()
287: */
288: public final ArrayList<String> getColumnsName() {
289: ArrayList<String> colunas = AbstractPersistentObject.colunas
290: .get(this .getClass().getName());
291: if (colunas != null)
292: return colunas;
293: colunas = new ArrayList<String>();
294:
295: ArrayList<Field> fields = getAllDeclaredFields(Column.class);
296: for (Field field : fields)
297: if (!field.getAnnotation(Column.class).isPk())
298: colunas.add(field.getAnnotation(Column.class).nome());
299:
300: AbstractPersistentObject.colunas.put(this .getClass().getName(),
301: colunas);
302: return colunas;
303: }
304:
305: /**
306: * @see br.com.gfpshare.db.PersistentObject#getPkNames()
307: */
308: public final ArrayList<String> getPkNames() {
309: ArrayList<String> pks = AbstractPersistentObject.pks.get(this
310: .getClass().getName());
311: if (pks != null)
312: return pks;
313: pks = new ArrayList<String>();
314:
315: ArrayList<Field> fields = getAllDeclaredFields(Column.class);
316: for (Field field : fields) {
317: Column column = field.getAnnotation(Column.class);
318: if (column.isPk()) {
319: pks.add(column.nome());
320: }
321: }
322:
323: AbstractPersistentObject.pks
324: .put(this .getClass().getName(), pks);
325: return pks;
326: }
327:
328: /**
329: * Retorna todos campos da calsse (incluindo superclasses)
330: * que possuam a anotação passada como parametro
331: * @param annotation Anotação que os campos devem possuir para
332: * retornarem no ArrayList
333: * @return ArrayList com os atributos que atendem ao critério
334: */
335: private ArrayList<Field> getAllDeclaredFields(
336: Class<Column> annotation) {
337: ArrayList<Field> fields = new ArrayList<Field>();
338: Class<?> classe = getClass();
339:
340: while (classe.isAnnotationPresent(Table.class)) {
341: Field[] campo = classe.getDeclaredFields();
342: for (int i = 0; i < campo.length; i++) {
343: campo[i].getAnnotation(Column.class);
344: if (campo[i].isAnnotationPresent(annotation)) {
345: fields.add(campo[i]);
346: }
347: }
348: classe = classe.getSuperclass();
349: if (classe == null)
350: throw new InvalidSubClassException(
351: "Your class must define a @Tabela anotation");
352: }
353: return fields;
354: }
355:
356: /**
357: * @see br.com.gfpshare.db.PersistentObject#getTableName()
358: */
359: public final String getTableName() {
360: Class<?> classe = getClass();
361: while (!classe.isAnnotationPresent(Table.class)) {
362: classe = classe.getSuperclass();
363: if (classe == null)
364: throw new InvalidSubClassException(
365: "Your class must define a @Tabela anotation");
366: }
367: return classe.getAnnotation(Table.class).name();
368: }
369:
370: /**
371: * @see br.com.gfpshare.db.PersistentObject#getAsMap()
372: */
373: public final Map<String, Object> getAsMap()
374: throws DataAccessException {
375: HashMap<String, Object> dados = new HashMap<String, Object>();
376: try {
377: ArrayList<Field> fields = getAllDeclaredFields(Column.class);
378: for (Field field : fields) {
379: Column colunaAnnotation = field
380: .getAnnotation(Column.class);
381: dados.put(colunaAnnotation.nome(), getClass()
382: .getMethod(colunaAnnotation.readMethodName(),
383: new Class[] {}).invoke(this ,
384: (Object[]) null));
385: }
386: } catch (Exception e) {
387: throw new DataAccessException(
388: "Problemas ao converter objeto para Map.", e);
389: }
390: return dados;
391: }
392:
393: /**
394: * @see br.com.gfpshare.db.PersistentObject#setDados(java.util.Map)
395: */
396: public void setDados(Map<String, Object> dados)
397: throws DataAccessException {
398: ArrayList<Field> fields = getAllDeclaredFields(Column.class);
399: for (Field field : fields) {
400: try {
401: Column colunaAnnotation = field
402: .getAnnotation(Column.class);
403:
404: Object valor = null;
405: if ((valor = dados.get(colunaAnnotation.nome())) != null) {
406: //Os campos Float são uma exceção, caso nós não façamos a conversão
407: //explicita a JVM vai tentar passá-lo como Double para o método causando uma exceção
408: if (field.getType().isAssignableFrom(Float.class))
409: getClass().getMethod(
410: colunaAnnotation.writeMethodName(),
411: Float.class).invoke(this ,
412: Float.valueOf(valor.toString()));
413: else
414: getClass().getMethod(
415: colunaAnnotation.writeMethodName(),
416: field.getType()).invoke(this , valor);
417: }
418: } catch (Exception e) {
419: throw new DataAccessException(
420: "Problemas ao converter Map para objeto, campo: "
421: + field.getName(), e);
422: }
423: }
424: }
425:
426: /**
427: * @param sql
428: * @param incluirWhere
429: * @param incluirOrderBy
430: * @return String
431: */
432: public String getSQL(String sql, boolean incluirWhere,
433: boolean incluirOrderBy) {
434: currentStatement = new ParsedPreparedStatement();
435: if (incluirWhere) {
436: ParsedPreparedStatement temp = ((AbstractSQLParser) getSqlParser())
437: .getWhere(getAsMap(),
438: AbstractPersistentObject.allColumns
439: .get(this .getClass().getName()),
440: " and ", condicoesExtras);
441: currentStatement.sql = sql
442: + " "
443: + temp.sql
444: + (incluirOrderBy ? ((AbstractSQLParser) getSqlParser())
445: .getOrderBy(getOrderBy(), crescente)
446: : "");
447: currentStatement.params = temp.params;
448: } else {
449: currentStatement.sql = sql
450: + " "
451: + (incluirOrderBy ? ((AbstractSQLParser) getSqlParser())
452: .getOrderBy(getOrderBy(), crescente)
453: : "");
454: }
455: return getSqlParser().parse(currentStatement).sql;
456: }
457:
458: public void clearAllFields() {
459: currentStatement = new ParsedPreparedStatement();
460: ArrayList<Field> fields = new ArrayList<Field>();
461: Class classe = getClass();
462: while (classe != AbstractPersistentObject.class) {
463: Field[] campo = classe.getDeclaredFields();
464: for (int i = 0; i < campo.length; i++) {
465: fields.add(campo[i]);
466: }
467: classe = classe.getSuperclass();
468: if (classe == null)
469: throw new InvalidSubClassException(
470: "Your class must define a @Tabela anotation");
471: }
472:
473: for (int i = 0; i < fields.size(); i++) {
474: if (Modifier.isFinal(fields.get(i).getModifiers()))
475: continue;
476: fields.get(i).setAccessible(true);
477: try {
478: fields.get(i).set(this , null);
479: } catch (IllegalArgumentException e) {
480: // TODO Auto-generated catch block
481: e.printStackTrace();
482: } catch (IllegalAccessException e) {
483: // TODO Auto-generated catch block
484: e.printStackTrace();
485: }
486: }
487: }
488: }
|