KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > storage > implementation > database > ViewDatabaseStorageManager


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.storage.implementation.database;
11
12 import java.sql.SQLException JavaDoc;
13 import java.sql.Statement JavaDoc;
14 import java.util.*;
15
16 import org.mmbase.bridge.Field;
17 import org.mmbase.bridge.NodeManager;
18 import org.mmbase.core.CoreField;
19 import org.mmbase.module.core.MMObjectBuilder;
20 import org.mmbase.module.core.MMObjectNode;
21 import org.mmbase.storage.StorageError;
22 import org.mmbase.storage.StorageException;
23 import org.mmbase.storage.util.Index;
24 import org.mmbase.storage.util.Scheme;
25 import org.mmbase.util.logging.Logger;
26 import org.mmbase.util.logging.Logging;
27
28 /**
29  * @javadoc
30  *
31  * @version $Id: ViewDatabaseStorageManager.java,v 1.7 2005/12/09 14:25:32 nklasens Exp $
32  * @since MMBase-1.8
33  */

34 public class ViewDatabaseStorageManager extends DatabaseStorageManager {
35
36     private static final Logger log = Logging.getLoggerInstance(ViewDatabaseStorageManager.class);
37     
38     /**
39      * Determine if the basic storage elements exist
40      * Basic storage elements include the 'object' storage (where all objects and their types are registered).
41      * @return <code>true</code> if basic storage elements exist
42      * @throws StorageException if an error occurred while querying the storage
43      */

44     public boolean exists() throws StorageException {
45         return viewExists(factory.getMMBase().getRootBuilder());
46     }
47     
48     /**
49      * Determine if a storage element exists for storing the given builder's objects
50      * @param builder the builder to check
51      * @return <code>true</code> if the storage element exists, false if it doesn't
52      * @throws StorageException if an error occurred while querying the storage
53      */

54     public boolean exists(MMObjectBuilder builder) throws StorageException {
55         return viewExists(builder);
56     }
57
58     /**
59      * Create the basic elements for this storage
60      * @throws StorageException if an error occurred during the creation of the object storage
61      */

62     public void create() throws StorageException {
63         if(!viewExists(factory.getMMBase().getRootBuilder())) {
64             viewCreate(factory.getMMBase().getRootBuilder());
65             createSequence();
66         }
67     }
68
69     /**
70      * Create a storage element to store the specified builder's objects.
71      * @param builder the builder to create the storage element for
72      * @throws StorageException if an error occurred during the creation of the storage element
73      */

74     public void create(MMObjectBuilder builder) throws StorageException {
75         if(!viewExists(builder)){
76              viewCreate(builder);
77         }
78     }
79   
80     public void create(final MMObjectNode node, final MMObjectBuilder builder) throws StorageException {
81         boolean localTransaction = !inTransaction;
82         if (localTransaction) {
83             beginTransaction();
84         }
85         try {
86             if (factory.hasOption("database-supports-insert-triggers")) {
87                 // no need for any fancy looping over parents; we just insert everything in this view
88
super.create(node, builder);
89             } else {
90                 // insert in parent tables (from parents to childs) (especially because foreign keys on object's number may exist)
91
java.util.Iterator JavaDoc i = builder.getAncestors().iterator();
92                 while(i.hasNext()) {
93                     MMObjectBuilder b = (MMObjectBuilder) i.next();
94                     createObject(node, b);
95                 }
96                 createObject(node, builder);
97             }
98             if (localTransaction) {
99                 commit();
100             }
101         } catch (StorageException se) {
102             if (localTransaction && inTransaction) rollback();
103             throw se;
104         }
105     }
106     
107     /**
108      * This method inserts a new object in a specific builder, and registers the change.
109      * This method makes it easier to implement relational databases, where you may need to update the node
110      * in more than one builder.
111      * Call this method for all involved builders if you use a relational database.
112      * @param node The node to insert. The node already needs to have a (new) number assigned
113      * @param builder the builder to store the node
114      * @throws StorageException if an error occurred during creation
115      */

116     protected void createObject(MMObjectNode node, MMObjectBuilder builder) throws StorageException {
117         List createFields = new ArrayList();
118         List builderFields = builder.getFields(NodeManager.ORDER_CREATE);
119         for (Iterator f = builderFields.iterator(); f.hasNext();) {
120             CoreField field = (CoreField)f.next();
121             if (field.inStorage() && (!this.isInheritedField(field) || field.getName().equals(this.getNumberField().getName()))) {
122                 createFields.add(field);
123             }
124         }
125         String JavaDoc tablename = getTableName(builder);
126         create(node, createFields, tablename);
127     }
128
129     /**
130      * Changes a node in the passed builder and all its parent builders
131      * @param node The node to change
132      * @param builder the builder to change the node in
133      * @throws StorageException if an error occurred during change
134      */

135     public void change(MMObjectNode node, MMObjectBuilder builder) throws StorageException {
136         boolean localTransaction = !inTransaction;
137         if (localTransaction) {
138             beginTransaction();
139         }
140         try {
141             if (factory.hasOption("database-supports-update-triggers")) {
142                super.change(node, builder);
143             } else {
144                 do {
145                     changeObject(node,builder);
146                     builder = builder.getParentBuilder();
147                 } while (builder!=null);
148             }
149             if (localTransaction) {
150                 commit();
151             }
152         } catch (StorageException se) {
153             if (localTransaction && inTransaction) rollback();
154             throw se;
155         }
156     }
157
158     private void changeObject(MMObjectNode node, MMObjectBuilder builder) {
159         List changeFields = new ArrayList();
160         // obtain the node's changed fields
161
Collection fieldNames = node.getChanged();
162         for (Iterator f = fieldNames.iterator(); f.hasNext();) {
163             String JavaDoc key = (String JavaDoc)f.next();
164             CoreField field = builder.getField(key);
165             if ((field != null) && field.inStorage() && !isInheritedField(field)) {
166                 changeFields.add(field);
167             }
168         }
169         change(node, builder, getTableName(builder), changeFields);
170     }
171
172     /**
173      * Deletes a node in the passed builder and all its parent builders.
174      * @param node The node to delete
175      * @param builder the builder to delete the node in
176      * @throws StorageException if an error occurred during delete
177      */

178     public void delete(MMObjectNode node, MMObjectBuilder builder) throws StorageException {
179         boolean localTransaction = !inTransaction;
180         if (localTransaction) {
181             beginTransaction();
182         }
183         
184         try {
185             if (factory.hasOption("database-supports-delete-triggers")) {
186                 super.delete(node, builder);
187             } else {
188                 do {
189                     deleteObject(node, builder);
190                     builder = builder.getParentBuilder();
191                 } while (builder!=null);
192             }
193             if (localTransaction) {
194                 commit();
195             }
196         } catch (StorageException se) {
197             if (localTransaction && inTransaction) rollback();
198             throw se;
199         }
200     }
201     
202     private void deleteObject(MMObjectNode node, MMObjectBuilder builder) {
203         List blobFileField = new ArrayList();
204         List builderFields = builder.getFields(NodeManager.ORDER_CREATE);
205         for (Iterator f = builderFields.iterator(); f.hasNext();) {
206             CoreField field = (CoreField)f.next();
207             if (field.inStorage() && !isInheritedField(field)) {
208                 if (factory.hasOption(Attributes.STORES_BINARY_AS_FILE) && (field.getType() == Field.TYPE_BINARY)) {
209                     blobFileField.add(field);
210                 }
211             }
212         }
213         String JavaDoc tablename = getTableName(builder);
214         super.delete(node, builder, blobFileField, tablename);
215     }
216
217     public String JavaDoc getFieldName(CoreField field) {
218         return (String JavaDoc)factory.getStorageIdentifier(field);
219     }
220   
221     public boolean isInheritedField(CoreField field) {
222         MMObjectBuilder inheritedBuilder = field.getParent().getParentBuilder();
223         if(inheritedBuilder == null) {
224             // no parent, thus cannot inherit anything
225
return false;
226         }
227         return (inheritedBuilder.getField(field.getName()) != null);
228     }
229     
230     public CoreField getNumberField() {
231         return factory.getMMBase().getRootBuilder().getField("number");
232     }
233
234     public String JavaDoc getTableName(MMObjectBuilder builder) {
235         if (builder.getParentBuilder() == null) {
236             return (String JavaDoc) factory.getStorageIdentifier(builder);
237         } else {
238             return getTableName((String JavaDoc) factory.getStorageIdentifier(builder));
239         }
240     }
241
242     public String JavaDoc getTableName(String JavaDoc viewname) {
243         String JavaDoc id = (String JavaDoc)factory.getStorageIdentifier(viewname + "_table");
244         String JavaDoc toCase = (String JavaDoc)factory.getAttribute(org.mmbase.storage.Attributes.STORAGE_IDENTIFIER_CASE);
245         if ("lower".equals(toCase)) {
246             return id.toLowerCase();
247         } else if ("upper".equals(toCase)) {
248             return id.toUpperCase();
249         } else {
250             return id;
251         }
252     }
253
254     public String JavaDoc getViewName(MMObjectBuilder builder) {
255         return getViewName((String JavaDoc)factory.getStorageIdentifier(builder));
256     }
257     public String JavaDoc getViewName(String JavaDoc viewname) {
258         return viewname;
259     }
260
261     /**
262      * Override the default version. An index should only be created if
263      * all the fields are in this builder. Otherwise this will fail horrably.
264      */

265     protected void create(Index index) throws StorageException {
266         for (int i=0; i<index.size(); i++) {
267             CoreField f = (CoreField)index.get(i);
268             if (!isPartOfBuilderDefinition(f)) {
269                 return;
270             }
271         }
272         
273         super.createIndex(index, getTableName(index.getParent()));
274     }
275
276     protected boolean exists(Index index) throws StorageException {
277         return super.exists(index, getTableName(index.getParent()));
278     }
279     
280     public boolean viewExists(MMObjectBuilder builder) {
281         return exists(getViewName(builder));
282     }
283     
284     public boolean viewCreate(MMObjectBuilder builder) {
285         MMObjectBuilder inheritedBuilder = builder.getParentBuilder();
286         // create the inherited builder first
287
if(inheritedBuilder != null) {
288             if(!viewExists(inheritedBuilder)) {
289                 // create the builder we inherit from
290
if(!viewCreate(inheritedBuilder)) {
291                     // we could not start create everyting!
292
return false;
293                 }
294             }
295         }
296         String JavaDoc tablename = getTableName(builder);
297         List fields = builder.getFields(NodeManager.ORDER_CREATE);
298
299         if (!super.exists(getTableName(builder))) {
300             List tableFields = new ArrayList();
301             for (Iterator f = fields.iterator(); f.hasNext();) {
302                 CoreField field = (CoreField)f.next();
303                 // is it a database field, and not of the parent(except the number field)?
304
if (isPartOfBuilderDefinition(field) || field.getName().equals(getNumberField().getName())) {
305                     tableFields.add(field);
306                 }
307             }
308             // Create the table
309
createTable(builder, tableFields, tablename);
310             
311             //TODO rewrite verify check with views
312
//verify(builder);
313
}
314
315         if (builder.getParentBuilder() != null) {
316             createView(builder, inheritedBuilder, fields, tablename);
317         }
318         return true;
319     }
320
321     private void createView(MMObjectBuilder builder, MMObjectBuilder inheritedBuilder, List fields, String JavaDoc tablename) throws StorageError {
322         log.debug("Creating a view for " + builder);
323         Scheme viewScheme = factory.getScheme(Schemes.CREATE_VIEW, Schemes.CREATE_VIEW_DEFAULT);
324         Scheme createInsertTriggerScheme = null;
325         Scheme createDeleteTriggerScheme = null;
326         Scheme createUpdateTriggerScheme = null;
327         if (factory.hasOption("database-supports-insert-triggers")) {
328             createInsertTriggerScheme = factory.getScheme(Schemes.CREATE_INSERT_TRIGGER, Schemes.CREATE_INSERT_TRIGGER_DEFAULT);
329             if (createInsertTriggerScheme == null) {
330                 log.warn("Database supports insert-triggers, but no trigger scheme defined! Ignoring insert-trigger!!");
331             }
332         }
333         if (factory.hasOption("database-supports-delete-triggers")) {
334             createDeleteTriggerScheme = factory.getScheme(Schemes.CREATE_DELETE_TRIGGER, Schemes.CREATE_DELETE_TRIGGER_DEFAULT);
335             if (createDeleteTriggerScheme == null) {
336                 log.warn("Database supports delete-triggers, but no trigger scheme defined! Ignoring delete-trigger!!");
337             }
338         }
339         if (factory.hasOption("database-supports-update-triggers")) {
340             createUpdateTriggerScheme = factory.getScheme(Schemes.CREATE_UPDATE_TRIGGER, Schemes.CREATE_UPDATE_TRIGGER_DEFAULT);
341             if (createUpdateTriggerScheme == null) {
342                 log.warn("Database supports update-triggers, but no trigger scheme defined! Ignoring update-trigger!!");
343             }
344         }
345
346         String JavaDoc viewname = getViewName(builder);
347         
348         StringBuffer JavaDoc createViewFields = new StringBuffer JavaDoc();
349         for (Iterator f = fields.iterator(); f.hasNext();) {
350             CoreField field = (CoreField)f.next();
351             if (field.inStorage() && (field.getType() != Field.TYPE_BINARY || !factory.hasOption(Attributes.STORES_BINARY_AS_FILE))) {
352                 if (createViewFields.length() > 0) {
353                     createViewFields.append(", ");
354                 }
355                 createViewFields.append(getFieldName(field));
356             }
357         }
358    
359         StringBuffer JavaDoc createTableFields = new StringBuffer JavaDoc();
360         Vector myFieldNames = new Vector();
361         Vector parentFieldNames = new Vector();
362
363         for (Iterator f = fields.iterator(); f.hasNext();) {
364             CoreField field = (CoreField)f.next();
365             if (field.inStorage() && (field.getType() != Field.TYPE_BINARY || !factory.hasOption(Attributes.STORES_BINARY_AS_FILE))) {
366    
367                 if (createTableFields.length() > 0) {
368                     createTableFields.append(", ");
369                 }
370                 if(isInheritedField(field)) {
371                     if(inheritedBuilder == null)
372                         throw new StorageError("Cannot have a inherited field while we dont extend inherit from a builder!");
373                     createTableFields.append(getViewName(inheritedBuilder) + "." + getFieldName(field));
374                     parentFieldNames.add(getFieldName(field));
375                 } else {
376                     createTableFields.append(tablename + "." + getFieldName(field));
377                     myFieldNames.add(getFieldName(field));
378                 }
379
380                 if (isInheritedField(field) && field.getName().equals(getNumberField().getName())) {
381                     myFieldNames.add(getFieldName(field));
382                 }
383             }
384         }
385         
386         String JavaDoc query = "";
387         try {
388             getActiveConnection();
389             // create the view
390
query = viewScheme.format(new Object JavaDoc[] { this, viewname, tablename, createViewFields.toString(), createTableFields.toString(), getFieldName(getNumberField()), inheritedBuilder, factory.getDatabaseName() });
391             // remove parenthesis with empty field definitions -
392
// unfortunately Schemes don't take this into account
393
if (factory.hasOption(Attributes.REMOVE_EMPTY_DEFINITIONS)) {
394                 query = query.replaceAll("\\(\\s*\\)", "");
395             }
396    
397             Statement JavaDoc s = activeConnection.createStatement();
398             long startTime = getLogStartTime();
399             s.executeUpdate(query);
400             s.close();
401             logQuery(query, startTime);
402
403             if (createInsertTriggerScheme != null) {
404                 //insert into mm_typedef_t (m_number, otype, owner) values (:NEW.m_number, :NEW.otype, :NEW.owner);
405
//insert into mm_object (m_number, name, description) values (:NEW.m_number, :NEW.name, :NEW.description);
406
StringBuffer JavaDoc myFields = new StringBuffer JavaDoc();
407                 StringBuffer JavaDoc myValues = new StringBuffer JavaDoc();
408                 StringBuffer JavaDoc parentFields = new StringBuffer JavaDoc();
409                 StringBuffer JavaDoc parentValues = new StringBuffer JavaDoc();
410                 for (int i=0; i<myFieldNames.size(); i++) {
411                     if (i > 0) {
412                         myFields.append(", ");
413                         myValues.append(", ");
414                     }
415                     myFields.append(myFieldNames.get(i));
416                     myValues.append(":NEW." + myFieldNames.get(i));
417                 }
418                 for (int i=0; i<parentFieldNames.size(); i++) {
419                     if (i > 0) {
420                         parentFields.append(", ");
421                         parentValues.append(", ");
422                     }
423                     parentFields.append(parentFieldNames.get(i));
424                     parentValues.append(":NEW." + parentFieldNames.get(i));
425                 }
426                 Object JavaDoc triggerName = factory.getStorageIdentifier(viewname + "_INSERT");
427                 query = createInsertTriggerScheme.format(new Object JavaDoc[]{this, viewname, tablename, inheritedBuilder, myFields.toString(), myValues.toString(), parentFields.toString(), parentValues.toString(), triggerName});
428
429                 if (factory.hasOption(Attributes.REMOVE_EMPTY_DEFINITIONS)) {
430                     query = query.replaceAll("\\(\\s*\\)", "");
431                 }
432    
433                 s = activeConnection.createStatement();
434                 long startTime2 = getLogStartTime();
435                 s.executeUpdate(query);
436                 s.close();
437                 logQuery(query, startTime2);
438             }
439
440             if (createDeleteTriggerScheme != null) {
441                 Object JavaDoc triggerName = factory.getStorageIdentifier(viewname + "_DELETE");
442                 query = createDeleteTriggerScheme.format(new Object JavaDoc[]{this, viewname, tablename, inheritedBuilder, getFieldName(getNumberField()), triggerName});
443                 if (factory.hasOption(Attributes.REMOVE_EMPTY_DEFINITIONS)) {
444                     query = query.replaceAll("\\(\\s*\\)", "");
445                 }
446    
447                 s = activeConnection.createStatement();
448                 long startTime2 = getLogStartTime();
449                 s.executeUpdate(query);
450                 s.close();
451                 logQuery(query, startTime2);
452             }
453
454             if (createUpdateTriggerScheme != null) {
455                 StringBuffer JavaDoc myAssignments = new StringBuffer JavaDoc();
456                 StringBuffer JavaDoc parentAssignments = new StringBuffer JavaDoc();
457                 for (int i=0; i<myFieldNames.size(); i++) {
458                     if (i > 0) {
459                         myAssignments.append(", ");
460                     }
461                     myAssignments.append(myFieldNames.get(i));
462                     myAssignments.append(" = :NEW.");
463                     myAssignments.append(myFieldNames.get(i));
464                 }
465                 for (int i=0; i<parentFieldNames.size(); i++) {
466                     if (i > 0) {
467                         parentAssignments.append(", ");
468                     }
469                     parentAssignments.append(parentFieldNames.get(i));
470                     parentAssignments.append(" = :NEW.");
471                     parentAssignments.append(parentFieldNames.get(i));
472                 }
473                 Object JavaDoc triggerName = factory.getStorageIdentifier(viewname + "_UPDATE");
474                 query = createUpdateTriggerScheme.format(new Object JavaDoc[]{this, viewname, tablename, inheritedBuilder, myAssignments.toString(), parentAssignments.toString(), getFieldName(getNumberField()), triggerName});
475
476                 if (factory.hasOption(Attributes.REMOVE_EMPTY_DEFINITIONS)) {
477                     query = query.replaceAll("\\(\\s*\\)", "");
478                 }
479    
480                 s = activeConnection.createStatement();
481                 long startTime2 = getLogStartTime();
482                 s.executeUpdate(query);
483                 s.close();
484                 logQuery(query, startTime2);
485             }
486    
487             tableNameCache.add(viewname.toUpperCase());
488         } catch (SQLException JavaDoc se) {
489             throw new StorageException(se.getMessage() + " in query:" + query, se);
490         } finally {
491             releaseActiveConnection();
492         }
493     }
494 }
495
Popular Tags