DatabaseObject.java

biz/hammurapi/sql/DatabaseObject.java

Violations

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

Source code

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 &lt;class name&gt;.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