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 }