Source code: nectar/data/DataAdapterService.java
1 /*
2 Copyright (C) 2003 Kai Schutte
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18 * SqlAdapter.java
19 *
20 * Created on March 13, 2003, 11:31 AM
21 */
22
23 package nectar.data;
24
25 import java.util.HashMap;
26 import java.util.Collection;
27 import java.util.Vector;
28 import java.util.List;
29 import java.util.Iterator;
30 import nectar.Service;
31 import nectar.ServiceException;
32 import nectar.configuration.ConfigurationException;
33 import nectar.record.Record;
34 import nectar.record.IdTree;
35
36 /** The DataAdapterService allows access to the DataSource configured in the struts_config.xml file.
37 *
38 * @author Kai Schutte skander@skander.com
39 */
40 public abstract class DataAdapterService extends Service {
41
42 /** Signal the beggining of a Transaction. The returned ConnectionHandle holds an active Connection to the DataSource, and will buffer data updates sent to the DataAdapter until {@link commitTransaction } is called.<p>
43 *
44 * You <B>MUST</B> absolutely liberate this connection with {@link commitTransaction } or {@link rollbackTransaction}, since the ConnectionHandle reserves a DataSource connection for exclusive use.
45 * @throws DataException Any Data IO related exceptions.
46 * @return The ConnectionHandle to the transaction locked connection.
47 */
48 public abstract ConnectionHandle beginTransaction() throws DataException;
49
50 public abstract void commitTransaction(ConnectionHandle ch) throws DataException;
51
52 public abstract void rollbackTransaction(ConnectionHandle cd) throws DataException;
53
54 /** Perfoms the query defined by the Query parameter Object, and returns the results
55 * as the [(Object) value].
56 */
57 public abstract Object readSingleFieldSingleRow(Query q) throws DataException;
58
59 /** Perfoms the query defined by the Query parameter Object, and returns the results
60 * as a [field] => [(Object) value] HashMap.
61 */
62 public abstract HashMap readMultipleFieldSingleRow(Query q) throws DataException;
63 /** Perfoms the query defined by the Query parameter Object, and returns the results
64 * as a List of [field] => [(Object) value] HashMap's.
65 */
66 public abstract List readMultipleFieldMultipleRow(Query q) throws DataException;
67 /** Perfoms the query defined by the Query parameter Object, and returns the results
68 * as a List of [(Object) value]'s.
69 */
70 public abstract List readSingleFieldMultipleRow(Query q) throws DataException;
71
72 /** Performs a query, retrieving the given <i>fields</i> from the given <i>tables</i> for the given record <i>id </i> and
73 * returns a [field] => [(Object) value] HashMap.
74 */
75 public HashMap getFieldsById(Collection fields, Collection tables, Long project, Long id) throws DataException {
76 Query q = new Query(fields, tables);
77 q.addDataCondition(DataConditions.AND, new OperatorCondition( new FieldElement(Record.TABLE, Record.FIELD_PROJECT), OperatorCondition.EQUAL, new ValueElement(project.toString())));
78 q.addDataCondition(DataConditions.AND, new OperatorCondition( new FieldElement(Record.TABLE, Record.FIELD_RECORD_ID), OperatorCondition.EQUAL, new ValueElement(id.toString())));
79 for (Iterator iter = tables.iterator(); iter.hasNext(); ) {
80 String table = (String)iter.next();
81 if (table.compareTo(Record.TABLE) != 0) {
82 q.addDataCondition(DataConditions.AND, new OperatorCondition( new FieldElement(table, "id"), OperatorCondition.EQUAL, new ValueElement(id.toString())));
83 }
84 }
85 q.addPostElement(new LimitPostElement(1));
86 return readMultipleFieldSingleRow(q);
87 }
88
89 public List getFieldsByIds(Collection fields, Collection tables, Collection ids) throws DataException {
90 Query q = new Query(fields, tables);
91 for (Iterator tableIter = tables.iterator(); tableIter.hasNext();) {
92 String table = (String)tableIter.next();
93 if (table.compareTo(Record.TABLE) != 0) {
94 q.addDataCondition(DataConditions.AND, new OperatorCondition( new FieldElement(Record.TABLE, Record.FIELD_RECORD_ID), OperatorCondition.EQUAL, new FieldElement(table, "id")));
95 }
96 }
97
98 DataConditions idDcs = new DataConditions();
99 for (Iterator i = ids.iterator(); i.hasNext(); ) {
100 Long id = (Long)i.next();
101 idDcs.append(DataConditions.OR, new OperatorCondition( new FieldElement(Record.TABLE, Record.FIELD_RECORD_ID), OperatorCondition.EQUAL, new ValueElement(id.toString())));
102 }
103 q.addDataCondition(DataConditions.AND, idDcs);
104 return readMultipleFieldMultipleRow(q);
105 }
106
107 /** Fetches the ID numbers of the children of the root record defined in the given IdTree.
108 * The ID numbers may refer to any record type -- the restrictions are to be
109 * defined in the Query parameter.<p>
110 *
111 * The root ID defined in the IdTree instance may be null, in which case the top level records of the tree will
112 * be retrieved, and the ID property at the top of the resulting IdTree will be
113 * null. <p>
114 *
115 * If the root ID defined in the IdTree instance is not null, it's ID number will appear as the ID property in the
116 * top level of the tree. <p>
117 *
118 * depth is the number of recursions to perform into the tree, so the tree depth.<p>
119 * @param q The Query restricting the contents of the resulting tree.
120 * @param tree An IdTree whose root ID number is the owner of the tree to fetch.
121 * @param depth The recursion depth into the tree.
122 * @throws DataException Any of the usual Data IO Exceptions.
123 * @return The resulting IdTree.
124 * @see nectar.record.RecordTree
125 * @see nectar.services.RecordService#loadTree
126 * @see nectar.record.IdTree
127 */
128 public IdTree getIdTree(Query q, IdTree tree, int depth) throws DataException {
129 Long topOwner = tree.getId();
130 if (depth > 0) {
131 Query tempQ = (Query)q.clone();
132 if (topOwner != null) {
133 tempQ.addDataCondition(DataConditions.AND, new OperatorCondition( new FieldElement(Record.TABLE, Record.FIELD_OWNER), OperatorCondition.EQUAL, new ValueElement( topOwner.toString())));
134 } else {
135 tempQ.addDataCondition(DataConditions.AND, new FunctionCondition( FunctionCondition.ISNULL, new FieldElement(Record.TABLE, Record.FIELD_OWNER)));
136 }
137 List ids = readMultipleFieldMultipleRow(tempQ);
138 for (Iterator i=ids.iterator(); i.hasNext();) {
139 java.util.Map map = (java.util.Map)i.next();
140 Long tmpId = (Long)map.get(Record.FIELD_RECORD_ID);
141
142 if (map.containsKey(Record.FIELD_TYPE)) {
143 String type = (String)map.get(Record.FIELD_TYPE);
144 if (depth > 1) {
145 IdTree it = new IdTree(tmpId, type);
146 tree.addChild( getIdTree(q, it, depth-1) );
147 } else {
148 tree.addChild(new IdTree(tmpId, type));
149 }
150 } else {
151 if (depth > 1) {
152 IdTree it = new IdTree(tmpId);
153 tree.addChild( getIdTree(q, it, depth-1) );
154 } else {
155 tree.addChild(new IdTree(tmpId));
156 }
157 }
158 }
159 }
160 return tree;
161 }
162
163 public abstract void insert(Insert i) throws DataException;
164
165 public abstract void insert(ConnectionHandle ch, Insert i) throws DataException;
166
167 public abstract void insert(ConnectionHandle ch, Insert i, boolean returnLastInsertId) throws DataException;
168
169 public abstract void update(Update update) throws DataException;
170
171 public abstract void update(ConnectionHandle ch, Update update) throws DataException;
172
173 public abstract void delete(ConnectionHandle ch, Delete delete) throws DataException;
174
175 public abstract void delete(Delete delete) throws DataException;
176
177 public void initService() throws ConfigurationException, ServiceException {
178 }
179
180 public void killService() {
181 killDependants();
182 }
183 }