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    }