001 /*
002 @license.text@
003 */
004 package biz.hammurapi.sql;
005
006 import java.lang.reflect.InvocationTargetException;
007 import java.sql.PreparedStatement;
008 import java.sql.ResultSet;
009 import java.sql.SQLException;
010 import java.util.ArrayList;
011 import java.util.Collection;
012 import java.util.Iterator;
013
014 import biz.hammurapi.sql.columns.Column;
015 import biz.hammurapi.sql.columns.ColumnChangeListener;
016
017 /**
018 * Base class for composite relationships where subitems exist only as part of the whole and removal of item from
019 * relationship is equivalent to deletion of the item.
020 * @author Pavel Vlasov
021 * @revision $Revision$
022 */
023 public class SimpleRelationship implements Relationship, ColumnChangeListener {
024 protected Collection inserted=new ArrayList();
025 protected Collection deleted=new ArrayList();
026 private DatabaseObject owner;
027 protected String tableName;
028 private boolean isLazy;
029 private String[][] keyInfo;
030 private Class itemClass;
031 private boolean isModified;
032 private Collection master;
033
034 /**
035 *
036 * @param owner Relationship owner.
037 * @param tableName Table where child item are stored.
038 * @param keyInfo Mapping of owner's primary key columns to child foreign key columns.
039 * @param isLazy indicates whether relationship is lazy.
040 */
041 public SimpleRelationship(DatabaseObject owner, Class itemClass, String tableName, String[][] keyInfo, boolean isLazy) {
042 this.owner=owner;
043 this.tableName=tableName;
044 this.isLazy=isLazy;
045 this.keyInfo=keyInfo;
046 this.itemClass=itemClass;
047 }
048
049 public boolean isLazy() {
050 return isLazy;
051 }
052
053 public void store(SQLProcessor processor) throws SQLException {
054 Iterator it=inserted.iterator();
055 while (it.hasNext()) {
056 IDatabaseObject item=(IDatabaseObject) it.next();
057 item.insert(processor, tableName);
058 it.remove();
059 }
060
061 it=deleted.iterator();
062 while (it.hasNext()) {
063 ((IDatabaseObject) it.next()).delete(processor, tableName);
064 it.remove();
065 }
066 }
067
068 public void add(DatabaseObject item) {
069 if (!deleted.remove(item)) {
070 link(item);
071 inserted.add(item);
072 }
073 }
074
075 /**
076 * Sets foreign key fields.
077 * @param item
078 */
079 private void link(DatabaseObject item) {
080 for (int i=0; i<keyInfo.length; i++) {
081 Column source=owner.getColumn(keyInfo[i][0]);
082 Column target=item.getColumn(keyInfo[i][1]);
083 target.set(source);
084 }
085 }
086
087 public void remove(IDatabaseObject item) {
088 if (!inserted.remove(item)) {
089 deleted.add(item);
090 }
091 }
092
093 public void load(SQLProcessor processor, Collection receiver) throws SQLException {
094 StringBuffer sql=new StringBuffer("SELECT * FROM ");
095 sql.append(tableName);
096 sql.append(" WHERE ");
097 for (int i=0; i<keyInfo.length; i++) {
098 if (i>0) {
099 sql.append("AND ");
100 }
101
102 sql.append(keyInfo[i][1]);
103 sql.append("=?");
104 }
105
106 processor.project(
107 sql.toString(),
108 new Parameterizer() {
109
110 public void parameterize(PreparedStatement ps) throws SQLException {
111 for (int i=0; i<keyInfo.length; i++) {
112 owner.getColumn(keyInfo[i][0]).parameterize(ps, i+1, true);
113 }
114 }
115
116 },
117 new Projector() {
118
119 public Object project(ResultSet rs) throws SQLException {
120 try {
121 return itemClass.getConstructor(new Class[] {ResultSet.class}).newInstance(new Object[] {rs});
122 } catch (SecurityException e) {
123 throw new SQLExceptionEx("Cannot project to "+itemClass, e);
124 } catch (InstantiationException e) {
125 throw new SQLExceptionEx("Cannot project to "+itemClass, e);
126 } catch (IllegalAccessException e) {
127 throw new SQLExceptionEx("Cannot project to "+itemClass, e);
128 } catch (InvocationTargetException e) {
129 throw new SQLExceptionEx("Cannot project to "+itemClass, e);
130 } catch (NoSuchMethodException e) {
131 throw new SQLExceptionEx("Cannot project to "+itemClass, e);
132 }
133 }
134
135 },
136 receiver);
137 }
138
139 public boolean isModified() {
140 return isModified;
141 }
142
143 public void update(SQLProcessor processor, IDatabaseObject subItem) throws SQLException {
144 subItem.update(processor, tableName);
145 }
146
147 public Class getItemType() {
148 return itemClass;
149 }
150
151 public void onChange(Column column) {
152 for (int i=0; i<keyInfo.length; i++) {
153 if (keyInfo[i][0].equals(column.getName())) {
154 isModified=true;
155 }
156 }
157
158 if (isModified) {
159 Iterator it=master.iterator();
160 while (it.hasNext()) {
161 link((DatabaseObject) it.next());
162 }
163 }
164 }
165
166 public void setMaster(Collection master) {
167 this.master=master;
168 }
169 }