KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > genimen > djeneric > repository > rdbms > RdbmsExtent


1 /*
2  * Copyright (c) 2001-2005 by Genimen BV (www.genimen.com) All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, is permitted
5  * provided that the following conditions are met:
6  * - Redistributions of source code must retain the above copyright notice, this list of conditions
7  * and the following disclaimer.
8  * - Redistributions in binary form must reproduce the above copyright notice, this list of
9  * conditions and the following disclaimer in the documentation and/or other materials
10  * provided with the distribution.
11  * - All advertising materials mentioning features or use of this software must display the
12  * following acknowledgment: "This product includes Djeneric."
13  * - Products derived from this software may not be called "Djeneric" nor may
14  * "Djeneric" appear in their names without prior written permission of Genimen BV.
15  * - Redistributions of any form whatsoever must retain the following acknowledgment: "This
16  * product includes Djeneric."
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL GENIMEN BV, DJENERIC.ORG,
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package com.genimen.djeneric.repository.rdbms;
31
32 import java.sql.ResultSet JavaDoc;
33 import java.sql.SQLException JavaDoc;
34
35 import com.genimen.djeneric.repository.DjExtent;
36 import com.genimen.djeneric.repository.DjObject;
37 import com.genimen.djeneric.repository.DjSession;
38 import com.genimen.djeneric.repository.exceptions.DjenericException;
39 import com.genimen.djeneric.util.DjLogger;
40
41 /**
42  * An DjExtent defines the persistent structure for a specific type of {@link
43  * DjObject}. An DjExtent uses properties that define the type, length etc. for
44  * the properties to be persisted; so there is a direct correlation between a
45  * {@link com.genimen.djeneric.repository.DjProperty} and the properties of a
46  * DjObject.
47  *
48  *@author Wido Riezebos
49  *@created April 6, 2002
50  */

51
52 public class RdbmsExtent extends DjExtent
53 {
54   public RdbmsExtent(String JavaDoc objectType, String JavaDoc name, String JavaDoc alias, String JavaDoc internalCode, String JavaDoc title,
55                      String JavaDoc nameSingular, String JavaDoc namePlural)
56   {
57     super(objectType, name, alias, internalCode, title, nameSingular, namePlural);
58   }
59
60   public boolean isEmpty(DjSession session) throws DjenericException
61   {
62     return isEmpty(this, session);
63   }
64
65   protected String JavaDoc getTableName()
66   {
67     return getName();
68   }
69
70   protected String JavaDoc createWhereClause()
71   {
72     return createWhereClause("");
73   }
74
75   /**
76    * Creates a where clause based on a provided clause (may be empty/null) This
77    * method takes into account that there may be an extra column that stores
78    * type information to distinguish between object types. (Normally every type
79    * has it's own extent but there may be exceptions; for instance the direct
80    * mapped manager may use the same table to store sub-types too)
81    *
82    *@param addThis Description of the Parameter
83    *@return Description of the Return Value
84    */

85   protected String JavaDoc createWhereClause(String JavaDoc addThis)
86   {
87     if (multipleTypesInExtent())
88     {
89       String JavaDoc result = " where " + RdbmsPersistenceManager.OBJECT_TYPE_COLUMN + " = '" + getAlias() + "' ";
90       if (addThis != null && addThis.trim().length() != 0) result += " and " + addThis;
91       return result;
92     }
93     else
94     {
95       if (addThis == null || addThis.trim().length() == 0) return "";
96       return " where " + addThis;
97     }
98
99   }
100
101   /**
102    * Every extent is stored in it's own (virtual) table so a type column is not
103    * needed to distinguish the records of object types. This method just
104    * returns false;
105    *
106    *@return Description of the Return Value
107    */

108
109   public boolean multipleTypesInExtent()
110   {
111     return false;
112   }
113
114   /**
115    * Returns true if this extent contains records in Polymorph. This does not
116    * take into account any {@link DjObject}s that have been created but not yet
117    * committed! I.e. if a new object is created but not yet committed the
118    * extent used to store it's persistent data will return false on
119    * hasRecords(session)
120    *
121    *@param extent Description of the Parameter
122    *@param session Description of the Parameter
123    *@return The empty value
124    *@exception DjenericException Description of the Exception
125    */

126   private boolean isEmpty(DjExtent extent, DjSession session) throws DjenericException
127   {
128     boolean result = true;
129     RdbmsSession rses = (RdbmsSession) session;
130
131     String JavaDoc s1 = "select 1 from " + RdbmsPersistenceManager.MODEL_TABLE + " where exists(";
132
133     String JavaDoc s2 = "select 1 from " + ((RdbmsExtent) extent).getTableName() + createWhereClause();
134
135     RdbmsPersistenceManager mgr = (RdbmsPersistenceManager) ((RdbmsSession) session).getPersistenceManager();
136     String JavaDoc translated = mgr.external2internalStatement(s2);
137     String JavaDoc combined = s1 + translated + ")";
138
139     SqlStatement stmt = rses.getInternalSqlStatement(combined);
140
141     try
142     {
143       ResultSet JavaDoc rs = stmt.executeQuery();
144       if (rs.next())
145       {
146         result = false;
147         // at least one record!
148
}
149       rs.close();
150       stmt.close();
151
152       // If false return now (short circuit &&)
153
if (!result) return false;
154
155       DjExtent[] specializations = extent.getSpecializations();
156       for (int i = 0; i < specializations.length; i++)
157       {
158         // If false return now (short circuit &&)
159
if (!isEmpty(specializations[i], session)) return false;
160       }
161       return true;
162     }
163     catch (SQLException JavaDoc x)
164     {
165       throw new DjenericException(x);
166     }
167
168   }
169
170   /**
171    * Returns a {@link SqlStatement} that can be used to update a record in
172    * Polymorph with the values of a {@link DjObject} instance.
173    *
174    *@param session the session to be used for creating the
175    * SqlStatement in
176    *@param propertyNames the name of the properties to be used in the
177    * where clause of the update statement. The order of the names must
178    * correspond to the order of the values in the propertyValues parameter
179    *@param propertyValues the values of the properties to be used in
180    * the where clause of the update statement. The order of the names must
181    * correspond to the order of the values in the propertyNames parameter
182    * No parameter binding is done yet i.e. you must use {@link
183    * SqlStatement}.setXXX() for each propertyName UNLESS the property is
184    * NULL. (That is why the properties have to be provided in the first
185    * place, a property being NULL affects the update statement since 'where
186    * xx = :xx' is not supported by JDBC if xx == NULL. In that case 'where
187    * xx IS NULL' is generated.
188    *@return The updateStatement value
189    *@exception DjenericException Description of the Exception
190    */

191   protected SqlStatement getUpdateStatement(RdbmsSession session, String JavaDoc[] propertyNames, Object JavaDoc[] propertyValues)
192       throws DjenericException
193   {
194     String JavaDoc keyProperty = getIdProperty().getName();
195     String JavaDoc s = "update " + getTableName() + " set ";
196     boolean first = true;
197     for (int i = 0; i < getPropertyCount(); i++)
198     {
199       String JavaDoc name = getPropertyName(i);
200       if (!name.equalsIgnoreCase(keyProperty))
201       {
202         if (!first) s += ",";
203         first = false;
204         s += name + " = :" + name + "\n";
205       }
206     }
207
208     String JavaDoc wcl = "";
209     first = true;
210     for (int i = 0; i < propertyNames.length; i++)
211     {
212       // ignore blob fields; databases usually do not support where clauses with blobs in'em
213
if (getProperty(propertyNames[i]).isMappedToLong()) continue;
214       if (!first) wcl += "and ";
215       first = false;
216       if (propertyValues[i] != null)
217       {
218         wcl += propertyNames[i] + " = :org_" + propertyNames[i] + "\n";
219       }
220       else
221       {
222         wcl += propertyNames[i] + " is null\n";
223       }
224     }
225
226     s += createWhereClause(wcl);
227
228     SqlStatement result = session.getSqlStatement(s);
229     return result;
230   }
231
232   private String JavaDoc _insertStmt = null;
233
234   /**
235    * Returns a {@link SqlStatement} that can be used to insert a record into
236    * Polymorph with the values of a {@link DjObject} instance.
237    *
238    *@param session the session to be used for creating the
239    * SqlStatement in
240    *@return The insertStatement value
241    *@exception DjenericException Description of the Exception
242    */

243   protected SqlStatement getInsertStatement(RdbmsSession session) throws DjenericException
244   {
245     if (_insertStmt == null)
246     {
247       String JavaDoc s = "insert into " + getTableName() + "(";
248       boolean first = true;
249
250       if (multipleTypesInExtent())
251       {
252         s += RdbmsPersistenceManager.OBJECT_TYPE_COLUMN;
253         first = false;
254       }
255
256       for (int i = 0; i < getPropertyCount(); i++)
257       {
258         String JavaDoc name = getPropertyName(i);
259         if (!first) s += ",";
260         first = false;
261         s += name;
262       }
263       s += ")\nvalues(";
264       first = true;
265       if (multipleTypesInExtent())
266       {
267         s += "'" + getAlias() + "'";
268         first = false;
269       }
270
271       for (int i = 0; i < getPropertyCount(); i++)
272       {
273         String JavaDoc name = getPropertyName(i);
274         if (!first) s += ",";
275         first = false;
276         s += ":" + name;
277       }
278       s += ")";
279
280       SqlStatement result = session.getSqlStatement(s);
281       _insertStmt = result.getInternalSql();
282       return result;
283     }
284     else return session.getInternalSqlStatement(_insertStmt);
285   }
286
287   /**
288    * Returns a {@link SqlStatement} that can be used to delete a record in
289    * Polymorph with the values of a {@link DjObject} instance.
290    *
291    *@param session the session to be used for creating the
292    * SqlStatement in
293    *@param propertyNames the name of the properties to be used in the
294    * where clause of the update statement. The order of the names must
295    * correspond to the order of the values in the propertyValues parameter
296    *@param propertyValues the values of the properties to be used in
297    * the where clause of the update statement. The order of the names must
298    * correspond to the order of the values in the propertyNames parameter
299    * No parameter binding is done yet i.e. you must use {@link
300    * SqlStatement}.setXXX() for each propertyName UNLESS the property is
301    * NULL. (That is why the properties have to be provided in the first
302    * place, a property being NULL affects the update statement since 'where
303    * xx = :xx' is not supported by JDBC if xx == NULL. In that case 'where
304    * xx IS NULL' is generated.
305    *@return The deleteStatement value
306    *@exception DjenericException Description of the Exception
307    */

308   protected SqlStatement getDeleteStatement(RdbmsSession session, String JavaDoc[] propertyNames, Object JavaDoc[] propertyValues)
309       throws DjenericException
310   {
311     String JavaDoc s = "delete from " + getTableName();
312     String JavaDoc wcl = "";
313
314     boolean first = true;
315     for (int i = 0; i < propertyNames.length; i++)
316     {
317       // ignore blob fields; databases usually do not support where clauses with blobs in'em
318
if (getProperty(propertyNames[i]).isMappedToLong()) continue;
319       if (!first) wcl += "and ";
320       first = false;
321       if (propertyValues[i] != null)
322       {
323         wcl += propertyNames[i] + " = :org_" + propertyNames[i] + "\n";
324       }
325       else
326       {
327         wcl += propertyNames[i] + " is null\n";
328       }
329     }
330     s += createWhereClause(wcl);
331
332     SqlStatement result = session.getSqlStatement(s);
333     return result;
334   }
335
336   private String JavaDoc _selectStmt = null;
337
338   /**
339    * Returns a {@link SqlStatement} that can be used to retrieve a record
340    * identified by it's internal primary key (object id) from Polymorph
341    *
342    *@param session the session to be used for creating the
343    * SqlStatement in
344    *@return The selectStatement value
345    *@exception DjenericException Description of the Exception
346    */

347   protected SqlStatement getSelectStatement(RdbmsSession session) throws DjenericException
348   {
349     if (_selectStmt == null)
350     {
351       String JavaDoc keyProperty = getIdProperty().getName();
352       String JavaDoc s = "select * from " + getTableName() + createWhereClause(keyProperty + " = :" + keyProperty);
353       SqlStatement result = session.getSqlStatement(s);
354       _selectStmt = result.getInternalSql();
355       return result;
356     }
357     else return session.getInternalSqlStatement(_selectStmt);
358   }
359
360   /**
361    * Returns an exact deep copy of the extent
362    *
363    *@return Description of the Return Value
364    */

365   public Object JavaDoc clone()
366   {
367     RdbmsExtent nt = new RdbmsExtent(getObjectType(), getName(), getAlias(), getInternalCode(), getTitle(),
368         getNameSingular(), getNamePlural());
369     nt.setInternalId(getInternalId());
370
371     try
372     {
373       copyPropertiesInto(nt);
374     }
375     catch (DjenericException x)
376     {
377       DjLogger.log(x);
378       throw new RuntimeException JavaDoc("Internal error: RdbmsExtent.clone() failed");
379     }
380
381     return nt;
382   }
383
384   public Class JavaDoc getNativeTypeClass()
385   {
386     return Long JavaDoc.class;
387   }
388
389 }
Popular Tags