KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > ViewManager


1 /**
2  * com.mckoi.database.ViewManager 20 Mar 2003
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import java.util.HashMap JavaDoc;
28 import com.mckoi.database.global.BlobAccessor;
29 import com.mckoi.database.jdbc.SQLQuery;
30 import com.mckoi.util.IntegerVector;
31
32 /**
33  * A DatabaseConnection view manager. This controls adding, updating, deleting,
34  * and processing views inside the system view table.
35  *
36  * @author Tobias Downer
37  */

38
39 public class ViewManager {
40
41   /**
42    * The DatabaseConnection.
43    */

44   private DatabaseConnection connection;
45
46   /**
47    * The context.
48    */

49   private DatabaseQueryContext context;
50
51   /**
52    * Set to true when the connection makes changes to the view table through
53    * this manager.
54    */

55   private boolean view_table_changed;
56   
57   /**
58    * A local cache of ViewDef objects mapped by row id in the system view
59    * table. This cache is invalidated when changes are committed to the system
60    * view table.
61    */

62   private HashMap JavaDoc local_cache;
63   
64   /**
65    * Constructs the ViewManager for a DatabaseConnection.
66    */

67   ViewManager(DatabaseConnection connection) {
68     this.connection = connection;
69     this.context = new DatabaseQueryContext(connection);
70     this.local_cache = new HashMap JavaDoc();
71     this.view_table_changed = false;
72
73     // Attach a cache backed on the VIEW table which will invalidate the
74
// connection cache whenever the view table is modified.
75
connection.attachTableBackedCache(new TableBackedCache(Database.SYS_VIEW) {
76       public void purgeCacheOfInvalidatedEntries(
77                         IntegerVector added_rows, IntegerVector removed_rows) {
78         // If there were changed then invalidate the cache
79
if (view_table_changed) {
80           invalidateViewCache();
81           view_table_changed = false;
82         }
83         // Otherwise, if there were committed added or removed changes also
84
// invalidate the cache,
85
else if ((added_rows != null && added_rows.size() > 0) ||
86                  (removed_rows != null && removed_rows.size() > 0)) {
87           invalidateViewCache();
88         }
89       }
90     });
91
92   }
93
94   /**
95    * Returns the local cache of ViewDef objects. This cache is mapped from
96    * row_id to view object. The cache is invalidated when changes are
97    * committed to the system view table.
98    */

99   private HashMap JavaDoc getViewCache() {
100     return local_cache;
101   }
102
103   /**
104    * Invalidates the view cache.
105    */

106   private void invalidateViewCache() {
107     local_cache.clear();
108   }
109   
110   /**
111    * Given the SYS_VIEW table, this returns a new table that contains the
112    * entry with the given view name, or an empty result if the view is not
113    * found.
114    * Generates an error if more than 1 entry found.
115    */

116   private Table findViewEntry(DataTable table,
117                               TableName view_name) {
118
119     Operator EQUALS = Operator.get("=");
120
121     Variable schemav = table.getResolvedVariable(0);
122     Variable namev = table.getResolvedVariable(1);
123
124     Table t = table.simpleSelect(context, namev, EQUALS,
125                       new Expression(TObject.stringVal(view_name.getName())));
126     t = t.exhaustiveSelect(context, Expression.simple(
127                   schemav, EQUALS, TObject.stringVal(view_name.getSchema())));
128
129     // This should be at most 1 row in size
130
if (t.getRowCount() > 1) {
131       throw new RuntimeException JavaDoc(
132                       "Assert failed: multiple view entries for " + view_name);
133     }
134
135     // Return the entries found.
136
return t;
137
138   }
139
140   /**
141    * Returns true if the view with the given name exists.
142    */

143   public boolean viewExists(TableName view_name) {
144
145     DataTable table = connection.getTable(Database.SYS_VIEW);
146     return findViewEntry(table, view_name).getRowCount() == 1;
147
148   }
149   
150   /**
151    * Defines a view. If the view with the name has not been defined it is
152    * defined. If the view has been defined then it is overwritten with this
153    * information.
154    *
155    * @param view information that defines the view.
156    * @param query the query that forms the view.
157    * @param user the user that owns this view being defined.
158    */

159   public void defineView(ViewDef view, SQLQuery query, User user)
160                                                     throws DatabaseException {
161
162     DataTableDef data_table_def = view.getDataTableDef();
163     DataTable view_table = connection.getTable(Database.SYS_VIEW);
164
165     TableName view_name = data_table_def.getTableName();
166
167     // Create the view record
168
RowData rdat = new RowData(view_table);
169     rdat.setColumnDataFromObject(0, data_table_def.getSchema());
170     rdat.setColumnDataFromObject(1, data_table_def.getName());
171     rdat.setColumnDataFromObject(2, query.serializeToBlob());
172     rdat.setColumnDataFromObject(3, view.serializeToBlob());
173     rdat.setColumnDataFromObject(4, user.getUserName());
174
175     // Find the entry from the view that equals this name
176
Table t = findViewEntry(view_table, view_name);
177
178     // Delete the entry if it already exists.
179
if (t.getRowCount() == 1) {
180       view_table.delete(t);
181     }
182
183     // Insert the new view entry in the system view table
184
view_table.add(rdat);
185
186     // Notify that this database object has been successfully created.
187
connection.databaseObjectCreated(view_name);
188     
189     // Change to the view table
190
view_table_changed = true;
191
192   }
193
194   /**
195    * Deletes the view with the given name, or returns false if no entries were
196    * deleted from the view table.
197    */

198   public boolean deleteView(TableName view_name) throws DatabaseException {
199
200     DataTable table = connection.getTable(Database.SYS_VIEW);
201
202     // Find the entry from the view table that equal this name
203
Table t = findViewEntry(table, view_name);
204
205     // No entries so return false
206
if (t.getRowCount() == 0) {
207       return false;
208     }
209     
210     table.delete(t);
211
212     // Notify that this database object has been successfully dropped.
213
connection.databaseObjectDropped(view_name);
214
215     // Change to the view table
216
view_table_changed = true;
217
218     // Return that 1 or more entries were dropped.
219
return true;
220   }
221
222   /**
223    * Creates a ViewDef object for the given view name in the table. The
224    * access is cached through the given HashMap object.
225    * <p>
226    * We assume the access to the cache is limited to the current thread
227    * calling this method. We don't synchronize over the cache at any time.
228    */

229   private static ViewDef getViewDef(HashMap JavaDoc cache,
230                             TableDataSource view_table, TableName view_name) {
231
232     RowEnumeration e = view_table.rowEnumeration();
233     while (e.hasMoreRows()) {
234       int row = e.nextRowIndex();
235
236       String JavaDoc c_schema =
237                     view_table.getCellContents(0, row).getObject().toString();
238       String JavaDoc c_name =
239                     view_table.getCellContents(1, row).getObject().toString();
240
241       if (view_name.getSchema().equals(c_schema) &&
242           view_name.getName().equals(c_name)) {
243       
244         Object JavaDoc cache_key = new Long JavaDoc(row);
245         ViewDef view_def = (ViewDef) cache.get(cache_key);
246
247         if (view_def == null) {
248           // Not in the cache, so deserialize it and put it in the cache.
249
BlobAccessor blob =
250                 (BlobAccessor) view_table.getCellContents(3, row).getObject();
251           // Derserialize the blob
252
view_def = ViewDef.deserializeFromBlob(blob);
253           // Put this in the cache....
254
cache.put(cache_key, view_def);
255
256         }
257         return view_def;
258       }
259       
260     }
261
262     throw new StatementException("View '" + view_name + "' not found.");
263
264   }
265
266   /**
267    * Creates a ViewDef object for the given index value in the table. The
268    * access is cached through the given HashMap object.
269    * <p>
270    * We assume the access to the cache is limited to the current thread
271    * calling this method. We don't synchronize over the cache at any time.
272    */

273   private static ViewDef getViewDef(HashMap JavaDoc cache,
274                                     TableDataSource view_table, int index) {
275
276     RowEnumeration e = view_table.rowEnumeration();
277     int i = 0;
278     while (e.hasMoreRows()) {
279       int row = e.nextRowIndex();
280       
281       if (i == index) {
282         Object JavaDoc cache_key = new Long JavaDoc(row);
283         ViewDef view_def = (ViewDef) cache.get(cache_key);
284
285         if (view_def == null) {
286           // Not in the cache, so deserialize it and put it in the cache.
287
BlobAccessor blob =
288                 (BlobAccessor) view_table.getCellContents(3, row).getObject();
289           // Derserialize the blob
290
view_def = ViewDef.deserializeFromBlob(blob);
291           // Put this in the cache....
292
cache.put(cache_key, view_def);
293
294         }
295         return view_def;
296       }
297       
298       ++i;
299     }
300     throw new Error JavaDoc("Index out of range.");
301   }
302   
303   /**
304    * Returns a freshly deserialized QueryPlanNode object for the given view
305    * object.
306    */

307   public QueryPlanNode createViewQueryPlanNode(TableName view_name) {
308     DataTable table = connection.getTable(Database.SYS_VIEW);
309     return getViewDef(local_cache, table, view_name).getQueryPlanNode();
310   }
311   
312   /**
313    * Returns an InternalTableInfo object used to model the list of views
314    * that are accessible within the given Transaction object. This is used to
315    * model all views as regular tables accessible within a transaction.
316    * <p>
317    * Note that the 'ViewManager' parameter can be null if there is no backing
318    * view manager. The view manager is intended as a cache to improve the
319    * access speed of the manager.
320    */

321   static InternalTableInfo createInternalTableInfo(ViewManager manager,
322                                                    Transaction transaction) {
323     return new ViewInternalTableInfo(manager, transaction);
324   }
325
326   // ---------- Inner classes ----------
327

328   /**
329    * An object that models the list of views as table objects in a
330    * transaction.
331    */

332   private static class ViewInternalTableInfo
333                                          extends AbstractInternalTableInfo2 {
334
335     ViewManager view_manager;
336     HashMap JavaDoc view_cache;
337
338     ViewInternalTableInfo(ViewManager manager, Transaction transaction) {
339       super(transaction, Database.SYS_VIEW);
340       this.view_manager = manager;
341       if (view_manager == null) {
342         view_cache = new HashMap JavaDoc();
343       }
344       else {
345         view_cache = view_manager.getViewCache();
346       }
347     }
348
349     public String JavaDoc getTableType(int i) {
350       return "VIEW";
351     }
352
353     public DataTableDef getDataTableDef(int i) {
354       return getViewDef(view_cache,
355                  transaction.getTable(Database.SYS_VIEW), i).getDataTableDef();
356     }
357
358     public MutableTableDataSource createInternalTable(int i) {
359       throw new RuntimeException JavaDoc("Not supported for views.");
360     }
361
362   }
363
364 }
365
366
Popular Tags