Inspector | Message | Severity | Location |
---|---|---|---|
Java Inspector 048 | Copyrights information should be present in each file. | 1 | |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 170:25 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 177:65 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 225:33 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 233:33 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 288:25 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 393:17 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 410:25 |
Java Inspector 015 | Do not change parameter value. For comprehensibility, formal parameters should be final | 2 | 482:25 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 392:23 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 396:31 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 441:31 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 462:31 |
Java Inspector 049 | Use a Collection instead of arrays Object[] | 2 | 835:55 |
Java Inspector 068 | Do not use System.out and System.err to output logging messages. Use loggers instead. | 2 | 760:67 |
Java Inspector 068 | Do not use System.out and System.err to output logging messages. Use loggers instead. | 2 | 763:67 |
Java Inspector 068 | Do not use System.out and System.err to output logging messages. Use loggers instead. | 2 | 766:67 |
Java Inspector 068 | Do not use System.out and System.err to output logging messages. Use loggers instead. | 2 | 769:67 |
Java Inspector 070-A | Cyclomatic complexity is too high: 13, maximum allowed is 12 | 2 | 329:9 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 125:13 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 200:13 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 254:13 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 397:25 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 413:17 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 503:17 |
Java Inspector 073 [java.lang.StringBuffer] | In Java 5 use StringBuilder instead of StringBuffer if access is single-threaded, e.g. StringBuffer is used as a local variable . | 2 | 818:25 |
Java Inspector 075 | Do not change value of for loop variable. | 2 | 425:33 |
Java Inspector 077 | To reduce probability of NullPointerException, use "string literal".equals(variable) instead of variable.equals("string literal"). | 2 | 343:51 |
Java Inspector 081 | Avoid static collections, they can grow in size over time. | 2 | 657:9 |
Java Inspector 081 | Avoid static collections, they can grow in size over time. | 2 | 734:9 |
Java Inspector 082 | Parenthesis are redundant. | 2 | 132:40 |
Java Inspector 082 | Parenthesis are redundant. | 2 | 155:48 |
Java Inspector 082 | Parenthesis are redundant. | 2 | 209:48 |
Java Inspector 082 | Parenthesis are redundant. | 2 | 470:40 |
Java Inspector 083 | Do not use printStackTrace() for exception logging. | 2 | 761:66 |
Java Inspector 083 | Do not use printStackTrace() for exception logging. | 2 | 764:66 |
Java Inspector 083 | Do not use printStackTrace() for exception logging. | 2 | 767:66 |
Java Inspector 083 | Do not use printStackTrace() for exception logging. | 2 | 770:66 |
Java Inspector 087 | Chain exceptions. If exception is thrown from an exception handler (wrapping exceptions), pass the cause exception to the new exception constructor. | 2 | 354:47 |
Java Inspector 087 | Chain exceptions. If exception is thrown from an exception handler (wrapping exceptions), pass the cause exception to the new exception constructor. | 2 | 364:47 |
Java Inspector 089 | Undocumented field | 2 | 85:5 |
Java Inspector 089 | Undocumented method | 2 | 91:9 |
Java Inspector 089 | Constructor documentation is too short. It is only 2 words. Should be at least 3 words. | 2 | 98:9 |
Java Inspector 089 | Constructor is not properly documented | 2 | 109:9 |
Java Inspector 089 | Undocumented method | 2 | 113:5 |
Java Inspector 089 | Undocumented method | 2 | 124:9 |
Java Inspector 089 | Undocumented method | 2 | 166:13 |
Java Inspector 089 | Undocumented method | 2 | 198:9 |
Java Inspector 089 | Undocumented method | 2 | 220:13 |
Java Inspector 089 | Undocumented method | 2 | 253:9 |
Java Inspector 089 | Undocumented method | 2 | 285:13 |
Java Inspector 089 | Undocumented method | 2 | 308:9 |
Java Inspector 089 | Undocumented method | 2 | 329:9 |
Java Inspector 089 | Undocumented method | 2 | 372:9 |
Java Inspector 089 | Field documentation is too short. It is only 2 words. Should be at least 3 words. | 2 | 379:9 |
Java Inspector 089 | Parameter className is not documented | 2 | 391:9 |
Java Inspector 089 | Parameter contentHandler is not documented | 2 | 460:9 |
Java Inspector 089 | Undocumented method | 2 | 480:9 |
Java Inspector 089 | Undocumented method | 2 | 502:9 |
Java Inspector 089 | Undocumented method | 2 | 547:9 |
Java Inspector 089 | Undocumented method | 2 | 560:9 |
Java Inspector 089 | Undocumented method | 2 | 567:9 |
Java Inspector 089 | Undocumented method | 2 | 608:9 |
Java Inspector 089 | Undocumented exception CloneNotSupportedException | 2 | 621:9 |
Java Inspector 089 | Method return value is not documented | 2 | 621:9 |
Java Inspector 089 | Undocumented method | 2 | 632:9 |
Java Inspector 089 | Undocumented method | 2 | 641:9 |
Java Inspector 089 | Undocumented method | 2 | 648:5 |
Java Inspector 089 | Undocumented method | 2 | 653:9 |
Java Inspector 089 | Undocumented method | 2 | 673:9 |
Java Inspector 089 | Undocumented method | 2 | 689:9 |
Java Inspector 089 | Undocumented method | 2 | 693:9 |
Java Inspector 089 | Undocumented method | 2 | 697:9 |
Java Inspector 089 | Undocumented method | 2 | 704:9 |
Java Inspector 089 | Undocumented method | 2 | 715:9 |
Java Inspector 089 | Undocumented method | 2 | 726:9 |
Java Inspector 089 | Parameter columnName is not documented | 2 | 743:9 |
Java Inspector 089 | Parameter generatedType is not documented | 2 | 743:9 |
Java Inspector 089 | Method return value is not properly documented | 2 | 743:9 |
Java Inspector 089 | Undocumented field | 2 | 784:9 |
Java Inspector 089 | Undocumented method | 2 | 786:9 |
Java Inspector 089 | Undocumented method | 2 | 792:9 |
Java Inspector 089 | Undocumented method | 2 | 798:9 |
Java Inspector 089 | Method is not properly documented | 2 | 813:9 |
Java Inspector 089 | Undocumented method | 2 | 820:25 |
Java Inspector 089 | Undocumented method | 2 | 830:25 |
Java Inspector 089 | Undocumented method | 2 | 854:25 |
Java Inspector 089 | Undocumented parameter uri | 2 | 881:9 |
Java Inspector 089 | Return value documentation is too short. It is only 1 words. Should be at least 3 words. | 2 | 881:9 |
Java Inspector 024 | Avoid hardwired character literals | 3 | 393:47 |
Java Inspector 024 | Avoid hardwired character literals | 3 | 393:52 |
Java Inspector 024 | Avoid hardwired character literals | 3 | 394:49 |
Java Inspector 025 | Avoid hardwired numeric literals. Allowed literals: [1, -1, 0] | 3 | 402:44 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 125:46 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 127:23 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 135:35 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 138:31 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 148:23 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 157:35 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 160:31 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 200:46 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 202:23 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 211:35 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 214:31 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 254:46 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 256:23 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 263:35 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 275:23 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 278:31 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 280:27 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 282:23 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 316:81 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 321:58 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 338:56 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 343:52 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 346:56 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 354:74 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 364:74 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 396:76 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 397:60 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 400:43 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 403:51 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 417:51 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 422:51 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 485:50 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 485:59 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 486:22 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 498:72 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 504:28 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 509:44 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 513:28 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 663:88 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 707:60 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 718:60 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 729:60 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 750:111 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 760:68 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 760:105 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 763:68 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 763:105 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 766:68 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 766:105 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 769:68 |
Java Inspector 026 | Avoid hardwired string literals. Allowed literals: [] | 3 | 769:105 |
Java Inspector 051 | It is good practice to call in any case super() in a constructor. | 3 | 98:9 |
Java Inspector 051 | It is good practice to call in any case super() in a constructor. | 3 | 109:9 |
Java Inspector 090 | Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). | 3 | 335:25 |
Java Inspector 090 | Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). | 3 | 578:9 |
Java Inspector 090 | Unnecessary else part in if. The main part terminates control flow (return, break, throw, or continue). | 3 | 580:16 |
1/*
2 * hgcommons 9
3 * Hammurapi Group Common Library
4 * Copyright (C) 2003 Hammurapi Group
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
21 * e-Mail: support@hammurapi.biz
22 */
23package biz.hammurapi.sql;
24
25import java.io.Serializable;
26import java.sql.PreparedStatement;
27import java.sql.SQLException;
28import java.sql.Types;
29import java.util.ArrayList;
30import java.util.Collection;
31import java.util.HashMap;
32import java.util.HashSet;
33import java.util.Iterator;
34import java.util.Map;
35import java.util.Properties;
36import java.util.Set;
37import java.util.Map.Entry;
38
39import org.w3c.dom.Element;
40import org.w3c.dom.Node;
41import org.xml.sax.Attributes;
42import org.xml.sax.ContentHandler;
43import org.xml.sax.SAXException;
44import org.xml.sax.helpers.DefaultHandler;
45
46import biz.hammurapi.config.ConfigurationException;
47import biz.hammurapi.config.Context;
48import biz.hammurapi.config.ContextConfigurable;
49import biz.hammurapi.config.DomConfigFactory;
50import biz.hammurapi.config.DomConfigurable;
51import biz.hammurapi.convert.Converter;
52import biz.hammurapi.convert.ConvertingService;
53import biz.hammurapi.sql.columns.Column;
54import biz.hammurapi.sql.columns.ColumnChangeListener;
55import biz.hammurapi.util.Attributable;
56import biz.hammurapi.util.ClassResourceLoader;
57import biz.hammurapi.util.Observable;
58import biz.hammurapi.util.Observer;
59import biz.hammurapi.util.Versioned;
60import biz.hammurapi.xml.dom.AbstractDomObject;
61import biz.hammurapi.xml.dom.DOMUtils;
62import biz.hammurapi.xml.dom.DomSerializable;
63
64
65/**
66 * SQLC-generated interface implementations implement this method to achieve
67 * differential update functionality - inserting and updating only modified fields.
68 * @author Pavel Vlasov
69 * @version $Revision: 1.11 $
70 */
71public class DatabaseObject
72 implements
73 DomSerializable,
74 ColumnChangeListener,
75 Cloneable,
76 ContextConfigurable,
77 Context,
78 DomConfigurable,
79 Attributable,
80 Versioned,
81 Observable,
82 IDatabaseObject,
83 Serializable {
84
85 protected Collection columns=new ArrayList();
86 private Map columnMap=new HashMap();
87 private Map columnXmlMap=new HashMap();
88 private boolean force;
89 private boolean isDeleted;
90
91 protected Column getColumn(String name) {
92 return (Column) columnMap.get(name);
93 }
94
95 /**
96 * Default constructor
97 */
98 public DatabaseObject() {
99 // Default constructor
100 }
101
102 /**
103 *
104 * @param force Forces columns to be marked as
105 * modified if setter method is invoked even if value being set equals to existing column
106 * value. Useful during inserts with non-nullable columns which map to primitive
107 * types and as such have default values.
108 */
109 public DatabaseObject(boolean force) {
110 this.force=force;
111 }
112
113 protected void addColumn(Column column) {
114 column.setForce(force);
115 columns.add(column);
116 columnMap.put(column.getName(), column);
117 columnXmlMap.put(column.getXmlName(), column);
118 column.setListener(this);
119 }
120
121 /* (non-Javadoc)
122 * @see biz.hammurapi.sql.IDatabaseObject#update(biz.hammurapi.sql.SQLProcessor, java.lang.String)
123 */
124 public int update(SQLProcessor processor, String tableName) throws SQLException {
125 StringBuffer sb=new StringBuffer("UPDATE ");
126 sb.append(tableName);
127 sb.append(" SET ");
128 boolean hasColumns=false;
129 Iterator it=columns.iterator();
130 while (it.hasNext()) {
131 Column column = (Column) it.next();
132 String colName=(column).listName();
133 if (colName!=null) {
134 if (hasColumns) {
135 sb.append(", ");
136 }
137 sb.append(colName);
138 sb.append("=?");
139 hasColumns=true;
140
141 }
142 }
143
144 if (!hasColumns) {
145 return 0;
146 }
147
148 sb.append(" WHERE ");
149
150 boolean hasPkColumns=false;
151 it=columns.iterator();
152 while (it.hasNext()) {
153 Column column = (Column) it.next();
154 if (column.isPrimaryKey()) {
155 String colName=(column).getName();
156 if (hasPkColumns) {
157 sb.append(" AND ");
158 }
159 sb.append(colName);
160 sb.append("=?");
161 hasPkColumns=true;
162 }
163 }
164
165 int ret=processor.processUpdate(sb.toString(), new Parameterizer() {
166 public int parameterize(PreparedStatement ps, int idx) throws SQLException {
167 Iterator it=columns.iterator();
168 while (it.hasNext()) {
169 Column column = (Column) it.next();
170 idx=column.parameterize(ps, idx, false);
171 }
172
173 it=columns.iterator();
174 while (it.hasNext()) {
175 Column column = (Column) it.next();
176 if (column.isPrimaryKey()) {
177 column.parameterizeOriginal(ps, idx++);
178 }
179 }
180 return idx;
181 }
182 });
183
184 it=columns.iterator();
185 while (it.hasNext()) {
186 ((Column) it.next()).clearModified();
187 }
188
189 originalVersion=objectVersion;
190 isModified=false;
191
192 return ret;
193 }
194
195 /* (non-Javadoc)
196 * @see biz.hammurapi.sql.IDatabaseObject#delete(biz.hammurapi.sql.SQLProcessor, java.lang.String)
197 */
198 public int delete(SQLProcessor processor, String tableName) throws SQLException {
199
200 StringBuffer sb=new StringBuffer("DELETE FROM ");
201 sb.append(tableName);
202 sb.append(" WHERE ");
203
204 boolean hasPkColumns=false;
205 Iterator it=columns.iterator();
206 while (it.hasNext()) {
207 Column column = (Column) it.next();
208 if (column.isPrimaryKey()) {
209 String colName=(column).getName();
210 if (hasPkColumns) {
211 sb.append(" AND ");
212 }
213 sb.append(colName);
214 sb.append("=?");
215 hasPkColumns=true;
216 }
217 }
218
219 int ret=processor.processUpdate(sb.toString(), new Parameterizer() {
220 public int parameterize(PreparedStatement ps, int idx) throws SQLException {
221 Iterator it=columns.iterator();
222 while (it.hasNext()) {
223 Column column = (Column) it.next();
224 if (!column.isPrimaryKey()) {
225 idx=column.parameterize(ps, idx, false);
226 }
227 }
228
229 it=columns.iterator();
230 while (it.hasNext()) {
231 Column column = (Column) it.next();
232 if (column.isPrimaryKey()) {
233 idx=column.parameterize(ps, idx, true);
234 }
235 }
236 return idx;
237 }
238 });
239
240 it=columns.iterator();
241 while (it.hasNext()) {
242 ((Column) it.next()).clearModified();
243 }
244
245 originalVersion=objectVersion;
246 isDeleted=true;
247 return ret;
248 }
249
250 /* (non-Javadoc)
251 * @see biz.hammurapi.sql.IDatabaseObject#insert(biz.hammurapi.sql.SQLProcessor, java.lang.String)
252 */
253 public int insert(SQLProcessor processor, String tableName) throws SQLException {
254 StringBuffer sb=new StringBuffer("INSERT INTO ");
255 sb.append(tableName);
256 sb.append(" (");
257 int columnsCounter=0;
258 Iterator it=columns.iterator();
259 while (it.hasNext()) {
260 String colName=((Column) it.next()).listName();
261 if (colName!=null) {
262 if (columnsCounter>0) {
263 sb.append(", ");
264 }
265 sb.append(colName);
266 columnsCounter++;
267
268 }
269 }
270
271 if (columnsCounter==0) {
272 return 0;
273 }
274
275 sb.append(") VALUES (");
276 for (int i=0; i<columnsCounter; i++) {
277 if (i>0) {
278 sb.append(", ");
279 }
280 sb.append("?");
281 }
282 sb.append(")");
283
284 int ret=processor.processUpdate(sb.toString(), new Parameterizer() {
285 public int parameterize(PreparedStatement ps, int idx) throws SQLException {
286 Iterator it=columns.iterator();
287 while (it.hasNext()) {
288 idx = ((Column) it.next()).parameterize(ps, idx, false);
289 }
290 return idx;
291 }
292 });
293
294 it=columns.iterator();
295 while (it.hasNext()) {
296 ((Column) it.next()).clearModified();
297 }
298
299 originalVersion=objectVersion;
300 isModified=false;
301
302 return ret;
303 }
304
305 /* (non-Javadoc)
306 * @see biz.hammurapi.sql.IDatabaseObject#fromDom(org.w3c.dom.Element)
307 */
308 public void fromDom(Element holder) throws ConfigurationException {
309 fromDom(holder, getNameMap(getClass()));
310 }
311
312 private void loadAttributes(Element holder) throws ConfigurationException {
313 DomConfigFactory dcf=new DomConfigFactory();
314 attributes.clear();
315 try {
316 Node attributesNode = DOMUtils.selectSingleNode(holder, "object-attributes");
317 if (attributesNode!=null) {
318 attributes.putAll((Map) dcf.create(attributesNode));
319 }
320 } catch (Exception e) {
321 throw new ConfigurationException("Cannot load database object attributes: "+e, e);
322 }
323
324 }
325
326 /* (non-Javadoc)
327 * @see biz.hammurapi.sql.IDatabaseObject#fromDom(org.w3c.dom.Element, java.util.Properties)
328 */
329 public void fromDom(Element holder, Properties nameMap) throws ConfigurationException {
330 Iterator it=columns.iterator();
331 while (it.hasNext()) {
332 Column column=(Column) it.next();
333 String nodeName = nameMap.getProperty(column.getName(), column.getName()).trim();
334
335 if (nodeName.length()==0) {
336 // Zero mapping
337 continue;
338 } else if (nodeName.startsWith("@")) {
339 // Attribute mapping
340 if (holder.hasAttribute(nodeName.substring(1))) {
341 column.load(holder.getAttribute(nodeName.substring(1)));
342 }
343 } else if (nodeName.equals(".")) {
344 // Text content mapping
345 column.load(AbstractDomObject.getElementText(holder));
346 } else if (nodeName.startsWith("!")) {
347 // Simple node mapping
348 try {
349 Node cNode=DOMUtils.selectSingleNode(holder, nodeName.substring(1));
350 if (cNode!=null) {
351 column.load(AbstractDomObject.getElementText(cNode));
352 }
353 } catch (Exception e) {
354 throw new ConfigurationException("Cannot load column "+column.getName());
355 }
356 } else {
357 // Regular node mapping
358 try {
359 Node cNode=DOMUtils.selectSingleNode(holder, nodeName);
360 if (cNode!=null) {
361 column.configure(cNode, null, getClass().getClassLoader());
362 }
363 } catch (Exception e) {
364 throw new ConfigurationException("Cannot load column "+column.getName());
365 }
366 }
367 }
368
369 loadAttributes(holder);
370 }
371
372 public void toDom(Element holder) {
373 toDom(holder, getNameMap(getClass()), false);
374 }
375
376 /**
377 * XML namespace.
378 */
379 protected String xmlNamespace;
380
381 /**
382 * Name of object XML Element.
383 */
384 protected String xmlElement;
385
386 /**
387 * Converts fully qualified class name to namespace and element name.
388 * @param className
389 * @return String array with two elements. First - namespace, second - element name
390 */
391 public static String[] xmlNames(String className) {
392 String[] ret={null, null};
393 className = className.replace('$', '.');
394 int idx = className.lastIndexOf('.');
395 if (idx!=-1) {
396 String[] pName = className.substring(0, idx).split("\\.");
397 StringBuffer sb = new StringBuffer("http://www.");
398 if (pName.length>1) {
399 sb.append(pName[1]);
400 sb.append(".");
401 sb.append(pName[0]);
402 for (int i=2; i<pName.length; ++i) {
403 sb.append("/");
404 sb.append(pName[i]);
405 }
406 ret[0] = sb.toString();
407 } else {
408 sb.append(pName[0]);
409 }
410 className = className.substring(idx+1);
411 }
412
413 StringBuffer sb = new StringBuffer();
414 for (int i=0, j=0, l=className.length(); i<=l; i++) {
415 if (i==l && j<i) {
416 if (sb.length()>0) {
417 sb.append("-");
418 }
419 sb.append(className.substring(j, i));
420 } else if (Character.isUpperCase(className.charAt(i)) && j<i && Character.isLowerCase(className.charAt(i-1))) {
421 if (sb.length()>0) {
422 sb.append("-");
423 }
424 sb.append(className.substring(j, i));
425 j=i;
426 }
427 }
428
429 ret[1]=sb.toString().toLowerCase();
430 return ret;
431 }
432
433 /**
434 * Serializes object to XML events
435 * @param contentHandler Events receiver
436 * @param withHolder If true outputs object XML element, otherwise only nested elements.
437 * @throws SAXException
438 */
439 public void toSax(ContentHandler contentHandler, boolean withHolder) throws SAXException {
440 if (xmlElement==null) {
441 String[] xmlNames = xmlNames(getClass().getName());
442 xmlElement=xmlNames[1];
443 xmlNamespace=xmlNames[0];
444 }
445 if (withHolder) {
446 contentHandler.startElement(xmlNamespace, xmlElement, xmlElement, null);
447 }
448
449 childrenToSax(contentHandler);
450 if (withHolder) {
451 contentHandler.endElement(xmlNamespace, xmlElement, xmlElement);
452 }
453 }
454
455 /**
456 * Outputs child objects to SAX.
457 * @param contentHandler
458 * @throws SAXException
459 */
460 protected void childrenToSax(ContentHandler contentHandler) throws SAXException {
461 if (xmlElement==null) {
462 String[] xmlNames = xmlNames(getClass().getName());
463 xmlElement=xmlNames[1];
464 xmlNamespace=xmlNames[0];
465 }
466
467 Iterator it=columns.iterator();
468 while (it.hasNext()) {
469 Column column = (Column) it.next();
470 String colName=(column).listName();
471 if (colName!=null) {
472 column.toSax(xmlNamespace, contentHandler);
473 }
474 }
475 }
476
477 /* (non-Javadoc)
478 * @see biz.hammurapi.sql.IDatabaseObject#toDom(org.w3c.dom.Element, java.util.Properties, boolean)
479 */
480 public void toDom(Element holder, Properties nameMap, boolean originals) {
481 if (nameMap==null) {
482 nameMap=new Properties();
483 }
484
485 String cna = nameMap.getProperty("@type", "type").trim();
486 if (!"".equals(cna)) {
487 holder.setAttribute(cna, getClass().getName());
488 }
489
490 Iterator it=columns.iterator();
491 while (it.hasNext()) {
492 Column column = (Column) it.next();
493 column.toDom(holder, nameMap.getProperty(column.getName(), column.getName()).trim(), originals);
494 }
495
496 if (!attributes.isEmpty()) {
497 DomSerializable ads = (DomSerializable) ConvertingService.convert(attributes, DomSerializable.class);
498 ads.toDom(AbstractDomObject.addElement(holder, "object-attributes"));
499 }
500 }
501
502 public String toString() {
503 StringBuffer ret=new StringBuffer(getClass().getName());
504 ret.append("[");
505 Iterator it=columns.iterator();
506 while (it.hasNext()) {
507 ret.append(it.next());
508 if (it.hasNext()) {
509 ret.append(", ");
510 }
511 }
512
513 ret.append("]");
514 return ret.toString();
515 }
516
517 /**
518 * Sets modified flag to true and increments version number.
519 * Also broadcasts the change to observers. Changed column is
520 * passed as second argument of update() method.
521 * Override this method in subclasses to react on
522 * change events, but don't forget to invoke
523 * super.onChange().
524 * @param column Changed column
525 */
526 public void onChange(Column column) {
527 isModified=true;
528
529 ++objectVersion;
530
531 if (column.isPrimaryKey()) {
532 isDeleted=false;
533 }
534
535 synchronized (observers) {
536 Iterator it=observers.iterator();
537 while (it.hasNext()) {
538 ((Observer) it.next()).update(this, column);
539 }
540 }
541
542 }
543
544 /* (non-Javadoc)
545 * @see biz.hammurapi.sql.IDatabaseObject#setOriginal()
546 */
547 public void setOriginal() {
548 objectVersion=originalVersion;
549 Iterator it=columns.iterator();
550 while (it.hasNext()) {
551 ((Column) it.next()).setOriginal();
552 }
553 }
554
555 private boolean isModified=false;
556
557 /* (non-Javadoc)
558 * @see biz.hammurapi.sql.IDatabaseObject#isModified()
559 */
560 public boolean isModified() {
561 return isModified;
562 }
563
564 /* (non-Javadoc)
565 * @see biz.hammurapi.sql.IDatabaseObject#isDeleted()
566 */
567 public boolean isDeleted() {
568 return isDeleted;
569 }
570
571 /**
572 * Two objects are considered equal and all their fields are equal.
573 * @param otherBean Other object
574 * @return true if object classes are equal and all member column values are
575 * equal.
576 */
577 public boolean equals(Object otherBean) {
578 if (otherBean==null) {
579 return false;
580 } else if (getClass().equals(otherBean.getClass())) {
581 Collection myColumns=new ArrayList(columns);
582 Collection otherColumns=new ArrayList(((DatabaseObject) otherBean).columns);
583 Iterator mcit=myColumns.iterator();
584 Z:
585 while (mcit.hasNext()) {
586 Column mc=(Column) mcit.next();
587 Iterator ocit=otherColumns.iterator();
588 while (ocit.hasNext()) {
589 Column oc=(Column) ocit.next();
590 if (mc.getName().equals(oc.getName())) {
591 if (mc.equals(oc)) {
592 ocit.remove();
593 mcit.remove();
594 continue Z;
595 }
596
597 return false;
598 }
599 }
600 }
601
602 return myColumns.isEmpty() && otherColumns.isEmpty();
603 } else {
604 return false;
605 }
606 }
607
608 public int hashCode() {
609 int ret=0;
610 Iterator cit=columns.iterator();
611 while (cit.hasNext()) {
612 ret^=cit.next().hashCode();
613 }
614 return ret;
615 }
616
617 /**
618 * Clones object, clears columns collection, clears isDeleted and isModified flags.
619 * Subclasses shall add cloned columns.
620 */
621 public Object clone() throws CloneNotSupportedException {
622 DatabaseObject ret = (DatabaseObject) super.clone();
623 ret.columns.clear();
624 ret.isDeleted=false;
625 ret.isModified=false;
626 return ret;
627 }
628
629 /* (non-Javadoc)
630 * @see biz.hammurapi.sql.IDatabaseObject#clear()
631 */
632 public void clear() {
633 Iterator it = columns.iterator();
634 while (it.hasNext()) {
635 ((Column) it.next()).clear();
636 }
637 isModified=false;
638 isDeleted=false;
639 }
640
641 public void configure(Context context, Converter converter) throws ConfigurationException {
642 Iterator it = columns.iterator();
643 while (it.hasNext()) {
644 ((Column) it.next()).configure(context, converter);
645 }
646 }
647
648 public Object get(String name) {
649 Column col=(Column) columnMap.get(name);
650 return col==null ? null : col.getObjectValue(false);
651 }
652
653 public void configure(Node configNode, Context context, ClassLoader classLoader) throws ConfigurationException {
654 fromDom((Element) configNode);
655 }
656
657 private static Map nnMap=new HashMap();
658
659 private static Properties getNameMap(Class clazz) {
660 synchronized (nnMap) {
661 Properties ret=(Properties) nnMap.get(clazz.getName());
662 if (ret==null) {
663 ret=new ClassResourceLoader(clazz).getProperties(null, "namemap");
664 nnMap.put(clazz.getName(), ret);
665 }
666 return ret;
667 }
668 }
669
670 /* (non-Javadoc)
671 * @see biz.hammurapi.sql.IDatabaseObject#copy(biz.hammurapi.sql.DatabaseObject)
672 */
673 public void copy(DatabaseObject source) {
674 Iterator it=columns.iterator();
675 while (it.hasNext()) {
676 Column targetColumn=(Column) it.next();
677 Column sourceColumn=(Column) source.columnMap.get(targetColumn.getName());
678 if (targetColumn.getClass().isInstance(sourceColumn)) { // Copy values only from compatible columns
679 targetColumn.set(sourceColumn);
680 if (targetColumn.isPrimaryKey()) {
681 targetColumn.clearModified();
682 }
683 }
684 }
685 }
686
687 private Map attributes=new HashMap();
688
689 public void setAttribute(Object key, Object value) {
690 attributes.put(key, value);
691 }
692
693 public Object getAttribute(Object key) {
694 return attributes.get(key);
695 }
696
697 public Object removeAttribute(Object key) {
698 return attributes.remove(key);
699 }
700
701 /* (non-Javadoc)
702 * @see biz.hammurapi.sql.IDatabaseObject#setColumnAttribute(java.lang.String, java.lang.Object, java.lang.Object)
703 */
704 public void setColumnAttribute(String columnName, Object key, Object value) {
705 Column column=(Column) columnMap.get(columnName);
706 if (column==null) {
707 throw new IllegalArgumentException("Column not found: "+columnName);
708 }
709 column.setAttribute(key, value);
710 }
711
712 /* (non-Javadoc)
713 * @see biz.hammurapi.sql.IDatabaseObject#getColumnAttribute(java.lang.String, java.lang.Object)
714 */
715 public Object getColumnAttribute(String columnName, Object key) {
716 Column column=(Column) columnMap.get(columnName);
717 if (column==null) {
718 throw new IllegalArgumentException("Column not found: "+columnName);
719 }
720 return column.getAttribute(key);
721 }
722
723 /* (non-Javadoc)
724 * @see biz.hammurapi.sql.IDatabaseObject#removeColumnAttribute(java.lang.String, java.lang.Object)
725 */
726 public Object removeColumnAttribute(String columnName, Object key) {
727 Column column=(Column) columnMap.get(columnName);
728 if (column==null) {
729 throw new IllegalArgumentException("Column not found: "+columnName);
730 }
731 return column.removeAttribute(key);
732 }
733
734 private static Map sqlTypes=new HashMap();
735
736 /**
737 * Allows to override generated column types with <class name>.sqltypes resource.
738 * Subclasses shall use this method when dealing with Object columns.
739 * @param columnName
740 * @param generatedType
741 * @return
742 */
743 protected int getSqlType(String columnName, int generatedType) {
744 Map typeMap;
745 synchronized (sqlTypes) {
746 String className = getClass().getName();
747 if (sqlTypes.containsKey(className)) {
748 typeMap=(Map) sqlTypes.get(className);
749 } else {
750 Properties literalMap=new ClassResourceLoader(getClass()).getProperties(null, "sqltypes");
751 typeMap=new HashMap();
752 sqlTypes.put(className, typeMap);
753 Iterator it=literalMap.entrySet().iterator();
754 while (it.hasNext()) {
755 Entry entry=(Entry) it.next();
756 try {
757 Integer type = (Integer) Types.class.getDeclaredField((String) entry.getValue()).get(null) ;
758 typeMap.put(entry.getKey(), type);
759 } catch (IllegalArgumentException e) {
760 System.err.println("Invalid SQL Type "+entry.getValue()+", ignored. Cause: "+e);
761 e.printStackTrace();
762 } catch (SecurityException e) {
763 System.err.println("Invalid SQL Type "+entry.getValue()+", ignored. Cause: "+e);
764 e.printStackTrace();
765 } catch (IllegalAccessException e) {
766 System.err.println("Invalid SQL Type "+entry.getValue()+", ignored. Cause: "+e);
767 e.printStackTrace();
768 } catch (NoSuchFieldException e) {
769 System.err.println("Invalid SQL Type "+entry.getValue()+", ignored. Cause: "+e);
770 e.printStackTrace();
771 }
772 }
773 }
774 }
775
776 Integer st=(Integer) typeMap.get(columnName);
777 return st==null ? generatedType : st.intValue();
778 }
779
780 /**
781 * Subclasses can choose to read object version from the database.
782 */
783 protected int objectVersion;
784 protected int originalVersion;
785
786 public int getObjectVersion() {
787 return objectVersion;
788 }
789
790 private Set observers = new HashSet();
791
792 public void addObserver(Observer observer) {
793 synchronized (observers) {
794 observers.add(observer);
795 }
796 }
797
798 public void removeObserver(Observer observer) {
799 synchronized (observers) {
800 observers.remove(observer);
801 }
802 }
803
804 private boolean equal(String str1, String str2) {
805 return str1==null ? str2==null : str1.equals(str2);
806 }
807
808 /**
809 * @param withHolder True if XML events stream contains start/endElement for
810 * this object.
811 * @return Content handler to populate database object by XML events.
812 */
813 public ContentHandler getContentHandler(final boolean withHolder) {
814 return new DefaultHandler() {
815 int level = withHolder ? -1 : 0;
816 private ContentHandler currentDelegate;
817 private Column currentColumn;
818 private StringBuffer buffer;
819
820 public void characters(char[] ch, int start, int length) throws SAXException {
821 if (currentDelegate==null) {
822 if (buffer!=null) {
823 buffer.append(ch, start, length);
824 }
825 } else {
826 currentDelegate.characters(ch, start, length);
827 }
828 }
829
830 public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
831
832 ++level;
833 if (level==1) {
834 if (xmlElement==null) {
835 String[] xmlNames = xmlNames(getClass().getName());
836 xmlElement=xmlNames[1];
837 xmlNamespace=xmlNames[0];
838 }
839
840 if (equal(xmlNamespace, uri)) {
841 currentColumn = (Column) columnXmlMap.get(localName);
842 if (currentColumn!=null) {
843 buffer = new StringBuffer();
844 return;
845 }
846 }
847
848 currentDelegate = getSubHandler(uri, localName, name);
849 } else if (currentDelegate!=null) {
850 currentDelegate.startElement(uri, localName, name, attributes);
851 }
852 }
853
854 public void endElement(String uri, String localName, String name) throws SAXException {
855 --level;
856 if (level==0) {
857 if (buffer!=null && currentColumn!=null) {
858 currentColumn.load(buffer.toString());
859 }
860
861 currentColumn=null;
862 buffer=null;
863 currentDelegate=null;
864 } else if (currentDelegate!=null) {
865 currentDelegate.endElement(uri, localName, name);
866 }
867 }
868
869 };
870 }
871
872 /**
873 * If database object receives XML event which doesn't map to any
874 * column, it invokes this method to obtain sub-handler for an element.
875 * Subclasses can override this method to populate relationships.
876 * This implementation returns default handler.
877 * @param name element local name
878 * @param qName element qualified name
879 * @return Sub-handler.
880 */
881 protected ContentHandler getSubHandler(String uri, String name, String qName) {
882 return null;
883 }
884
885 // TODO - Auditor, thread-local instance to listen for inserts, deletes and updates.
886
887}
888