001: /*
002: * hgcommons 7
003: * Hammurapi Group Common Library
004: * Copyright (C) 2003 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.biz/hammurapi-biz/ef/xmenu/hammurapi-group/products/products/hgcommons/index.html
021: * e-Mail: support@hammurapi.biz
022: */
023: package biz.hammurapi.sql;
024:
025: import java.lang.reflect.InvocationTargetException;
026: import java.sql.PreparedStatement;
027: import java.sql.ResultSet;
028: import java.sql.SQLException;
029: import java.util.ArrayList;
030: import java.util.Collection;
031: import java.util.Iterator;
032:
033: import biz.hammurapi.sql.columns.Column;
034: import biz.hammurapi.sql.columns.ColumnChangeListener;
035:
036: /**
037: * Base class for composite relationships where subitems exist only as part of the whole and removal of item from
038: * relationship is equivalent to deletion of the item.
039: * @author Pavel Vlasov
040: * @revision $Revision$
041: */
042: public class SimpleRelationship implements Relationship,
043: ColumnChangeListener {
044: protected Collection inserted = new ArrayList();
045: protected Collection deleted = new ArrayList();
046: private DatabaseObject owner;
047: protected String tableName;
048: private boolean isLazy;
049: private String[][] keyInfo;
050: private Class itemClass;
051: private boolean isModified;
052: private Collection master;
053:
054: /**
055: *
056: * @param owner Relationship owner.
057: * @param tableName Table where child item are stored.
058: * @param keyInfo Mapping of owner's primary key columns to child foreign key columns.
059: * @param isLazy indicates whether relationship is lazy.
060: */
061: public SimpleRelationship(DatabaseObject owner, Class itemClass,
062: String tableName, String[][] keyInfo, boolean isLazy) {
063: this .owner = owner;
064: this .tableName = tableName;
065: this .isLazy = isLazy;
066: this .keyInfo = keyInfo;
067: this .itemClass = itemClass;
068: }
069:
070: public boolean isLazy() {
071: return isLazy;
072: }
073:
074: public void store(SQLProcessor processor) throws SQLException {
075: Iterator it = inserted.iterator();
076: while (it.hasNext()) {
077: IDatabaseObject item = (IDatabaseObject) it.next();
078: item.insert(processor, tableName);
079: it.remove();
080: }
081:
082: it = deleted.iterator();
083: while (it.hasNext()) {
084: ((IDatabaseObject) it.next()).delete(processor, tableName);
085: it.remove();
086: }
087: }
088:
089: public void add(DatabaseObject item) {
090: if (!deleted.remove(item)) {
091: link(item);
092: inserted.add(item);
093: }
094: }
095:
096: /**
097: * Sets foreign key fields.
098: * @param item
099: */
100: private void link(DatabaseObject item) {
101: for (int i = 0; i < keyInfo.length; i++) {
102: Column source = owner.getColumn(keyInfo[i][0]);
103: Column target = item.getColumn(keyInfo[i][1]);
104: target.set(source);
105: }
106: }
107:
108: public void remove(IDatabaseObject item) {
109: if (!inserted.remove(item)) {
110: deleted.add(item);
111: }
112: }
113:
114: public void load(SQLProcessor processor, Collection receiver)
115: throws SQLException {
116: StringBuffer sql = new StringBuffer("SELECT * FROM ");
117: sql.append(tableName);
118: sql.append(" WHERE ");
119: for (int i = 0; i < keyInfo.length; i++) {
120: if (i > 0) {
121: sql.append("AND ");
122: }
123:
124: sql.append(keyInfo[i][1]);
125: sql.append("=?");
126: }
127:
128: processor.project(sql.toString(), new Parameterizer() {
129:
130: public void parameterize(PreparedStatement ps)
131: throws SQLException {
132: for (int i = 0; i < keyInfo.length; i++) {
133: owner.getColumn(keyInfo[i][0]).parameterize(ps,
134: i + 1, true);
135: }
136: }
137:
138: }, new Projector() {
139:
140: public Object project(ResultSet rs) throws SQLException {
141: try {
142: return itemClass.getConstructor(
143: new Class[] { ResultSet.class })
144: .newInstance(new Object[] { rs });
145: } catch (SecurityException e) {
146: throw new SQLExceptionEx("Cannot project to "
147: + itemClass, e);
148: } catch (InstantiationException e) {
149: throw new SQLExceptionEx("Cannot project to "
150: + itemClass, e);
151: } catch (IllegalAccessException e) {
152: throw new SQLExceptionEx("Cannot project to "
153: + itemClass, e);
154: } catch (InvocationTargetException e) {
155: throw new SQLExceptionEx("Cannot project to "
156: + itemClass, e);
157: } catch (NoSuchMethodException e) {
158: throw new SQLExceptionEx("Cannot project to "
159: + itemClass, e);
160: }
161: }
162:
163: }, receiver);
164: }
165:
166: public boolean isModified() {
167: return isModified;
168: }
169:
170: public void update(SQLProcessor processor, IDatabaseObject subItem)
171: throws SQLException {
172: subItem.update(processor, tableName);
173: }
174:
175: public Class getItemType() {
176: return itemClass;
177: }
178:
179: public void onChange(Column column) {
180: for (int i = 0; i < keyInfo.length; i++) {
181: if (keyInfo[i][0].equals(column.getName())) {
182: isModified = true;
183: }
184: }
185:
186: if (isModified) {
187: Iterator it = master.iterator();
188: while (it.hasNext()) {
189: link((DatabaseObject) it.next());
190: }
191: }
192: }
193:
194: public void setMaster(Collection master) {
195: this.master = master;
196: }
197: }
|