Mir goes GPL
[mir.git] / source / mir / storage / Database.java
1 /*
2  * Copyright (C) 2001, 2002  The Mir-coders group
3  *
4  * This file is part of Mir.
5  *
6  * Mir is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * Mir 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 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Mir; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * In addition, as a special exception, The Mir-coders gives permission to link
21  * the code of this program with the com.oreilly.servlet library, any library
22  * licensed under the Apache Software License, The Sun (tm) Java Advanced
23  * Imaging library (JAI), The Sun JIMI library (or with modified versions of
24  * the above that use the same license as the above), and distribute linked
25  * combinations including the two.  You must obey the GNU General Public
26  * License in all respects for all of the code used other than the above
27  * mentioned libraries.  If you modify this file, you may extend this exception
28  * to your version of the file, but you are not obligated to do so.  If you do
29  * not wish to do so, delete this exception statement from your version.
30  */
31
32 package mir.storage;
33
34 import  java.sql.*;
35 import  java.lang.*;
36 import  java.io.*;
37 import  java.util.*;
38 import  java.text.SimpleDateFormat;
39 import  java.text.ParseException;
40 import  freemarker.template.*;
41 import  com.codestudio.sql.*;
42 import  com.codestudio.util.*;
43
44 import  mir.storage.StorageObject;
45 import  mir.storage.store.*;
46 import  mir.entity.*;
47 import  mir.misc.*;
48
49
50 /**
51  * Diese Klasse implementiert die Zugriffsschicht auf die Datenbank.
52  * Alle Projektspezifischen Datenbankklassen erben von dieser Klasse.
53  * In den Unterklassen wird im Minimalfall nur die Tabelle angegeben.
54  * Im Konfigurationsfile findet sich eine Verweis auf den verwendeten
55  * Treiber, Host, User und Passwort, ueber den der Zugriff auf die
56  * Datenbank erfolgt.
57  *
58  * @version $Revision: 1.23 $ $Date: 2002/09/01 22:05:52 $
59  * @author $Author: mh $
60  *
61  * $Log: Database.java,v $
62  * Revision 1.23  2002/09/01 22:05:52  mh
63  * Mir goes GPL
64  *
65  * Revision 1.22  2002/08/25 19:00:09  mh
66  * merge of localization branch into HEAD. mh and zap
67  *
68  * Revision 1.21  2002/08/04 23:38:22  mh
69  * fix up the webdb_create update stuff
70  *
71  * Revision 1.20  2002/07/21 22:32:25  mh
72  * on insert, the "webdb_lastchange" field should get a value
73  *
74  * Revision 1.19  2002/06/29 15:44:46  mh
75  * make the webdb_create update be called webdb_create_update. it breaks things otherwise. a fixme case I know..
76  *
77  * Revision 1.18  2002/06/28 20:42:13  mh
78  * added necessary bits in templates and Database.java to make webdb_create modifiable. make the conversion from sql/Timestamp to String more robust
79  *
80  *
81  */
82 public class Database implements StorageObject {
83
84         protected String                    theTable;
85         protected String                    theCoreTable=null;
86         protected String                    thePKeyName="id";
87         protected int                       thePKeyType, thePKeyIndex;
88         protected boolean                   evaluatedMetaData=false;
89         protected ArrayList                 metadataFields,metadataLabels,
90                                                                                                                                                         metadataNotNullFields;
91         protected int[]                     metadataTypes;
92         protected Class                     theEntityClass;
93         protected StorageObject             myselfDatabase;
94         protected SimpleList                popupCache=null;
95         protected boolean                   hasPopupCache = false;
96         protected SimpleHash                hashCache=null;
97         protected boolean                   hasTimestamp=true;
98         private String                      database_driver, database_url;
99         private int                         defaultLimit;
100         protected DatabaseAdaptor           theAdaptor;
101         protected Logfile                   theLog;
102         private static Class                GENERIC_ENTITY_CLASS=null,
103                                       STORABLE_OBJECT_ENTITY_CLASS=null;
104   private static SimpleHash           POPUP_EMTYLINE=new SimpleHash();
105   protected static final ObjectStore  o_store=ObjectStore.getInstance();
106   private SimpleDateFormat _dateFormatterOut = 
107                                     new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
108   private SimpleDateFormat _dateFormatterIn = 
109                                     new SimpleDateFormat("yyyy-MM-dd HH:mm");
110   private Calendar _cal = new GregorianCalendar();
111
112   private static final int _millisPerHour = 60 * 60 * 1000;
113   private static final int _millisPerMinute = 60 * 1000;
114
115         static {
116                 // always same object saves a little space
117                 POPUP_EMTYLINE.put("key", ""); POPUP_EMTYLINE.put("value", "--");
118     try {
119       GENERIC_ENTITY_CLASS = Class.forName("mir.entity.StorableObjectEntity");
120       STORABLE_OBJECT_ENTITY_CLASS = Class.forName("mir.entity.StorableObjectEntity");
121     }
122     catch (Exception e) {
123       System.err.println("FATAL: Database.java could not initialize" + e.toString());
124     }
125   }
126
127
128         /**
129          * Kontruktor bekommt den Filenamen des Konfigurationsfiles übergeben.
130          * Aus diesem file werden <code>Database.Logfile</code>,
131          * <code>Database.Username</code>,<code>Database.Password</code>,
132          * <code>Database.Host</code> und <code>Database.Adaptor</code>
133          * ausgelesen und ein Broker für die Verbindugen zur Datenbank
134          * erzeugt.
135          *
136          * @param   String confFilename Dateiname der Konfigurationsdatei
137          */
138         public Database() throws StorageObjectException {
139                 theLog = Logfile.getInstance(MirConfig.getProp("Home")+
140                                                                                                                                 MirConfig.getProp("Database.Logfile"));
141                 String theAdaptorName=MirConfig.getProp("Database.Adaptor");
142                 defaultLimit = Integer.parseInt(MirConfig.getProp("Database.Limit"));
143                 try {
144                         theEntityClass = GENERIC_ENTITY_CLASS;
145                         theAdaptor = (DatabaseAdaptor)Class.forName(theAdaptorName).newInstance();
146                 } catch (Exception e){
147                         theLog.printError("Error in Database() constructor with "+
148                                                                                                 theAdaptorName + " -- " +e.toString());
149                         throw new StorageObjectException("Error in Database() constructor with "
150                                                                                                                                                          +e.toString());
151                 }
152                 /*String database_username=MirConfig.getProp("Database.Username");
153                 String database_password=MirConfig.getProp("Database.Password");
154                 String database_host=MirConfig.getProp("Database.Host");
155                 try {
156                         database_driver=theAdaptor.getDriver();
157                         database_url=theAdaptor.getURL(database_username,database_password,
158                                                                                                                                                 database_host);
159                         theLog.printDebugInfo("adding Broker with: " +database_driver+":"+
160                                                                                                                 database_url  );
161                         MirConfig.addBroker(database_driver,database_url);
162                         //myBroker=MirConfig.getBroker();
163                 }*/
164         }
165
166         /**
167          * Liefert die Entity-Klasse zurück, in der eine Datenbankzeile gewrappt
168          * wird. Wird die Entity-Klasse durch die erbende Klasse nicht überschrieben,
169          * wird eine mir.entity.GenericEntity erzeugt.
170          *
171          * @return Class-Objekt der Entity
172          */
173         public java.lang.Class getEntityClass () {
174                 return  theEntityClass;
175         }
176
177         /**
178          * Liefert die Standardbeschränkung von select-Statements zurück, also
179          * wieviel Datensätze per Default selektiert werden.
180          *
181          * @return Standard-Anzahl der Datensätze
182          */
183         public int getLimit () {
184                 return  defaultLimit;
185         }
186
187         /**
188          * Liefert den Namen des Primary-Keys zurück. Wird die Variable nicht von
189          * der erbenden Klasse überschrieben, so ist der Wert <code>PKEY</code>
190          * @return Name des Primary-Keys
191          */
192         public String getIdName () {
193                 return  thePKeyName;
194         }
195
196         /**
197          * Liefert den Namen der Tabelle, auf das sich das Datenbankobjekt bezieht.
198          *
199          * @return Name der Tabelle
200          */
201         public String getTableName () {
202                 return  theTable;
203         }
204
205         /*
206          *   Dient dazu vererbte Tabellen bei objectrelationalen DBMS
207          *   zu speichern, wenn die id einer Tabelle in der parenttabelle verwaltet
208          *   wird.
209          *   @return liefert theCoreTabel als String zurueck, wenn gesetzt, sonst
210          *    the Table
211          */
212
213         public String getCoreTable(){
214                 if (theCoreTable!=null) return theCoreTable;
215                 else return theTable;
216         }
217
218         /**
219          * Liefert Feldtypen der Felder der Tabelle zurueck (s.a. java.sql.Types)
220          * @return int-Array mit den Typen der Felder
221          * @exception StorageObjectException
222          */
223         public int[] getTypes () throws StorageObjectException {
224                 if (metadataTypes == null)
225                         get_meta_data();
226                 return  metadataTypes;
227         }
228
229         /**
230          * Liefert eine Liste der Labels der Tabellenfelder
231          * @return ArrayListe mit Labeln
232          * @exception StorageObjectException
233          */
234         public ArrayList getLabels () throws StorageObjectException {
235                 if (metadataLabels == null)
236                         get_meta_data();
237                 return  metadataLabels;
238         }
239
240         /**
241          * Liefert eine Liste der Felder der Tabelle
242          * @return ArrayList mit Feldern
243          * @exception StorageObjectException
244          */
245         public ArrayList getFields () throws StorageObjectException {
246                 if (metadataFields == null)
247                         get_meta_data();
248                 return  metadataFields;
249         }
250
251
252         /*
253          *   Gets value out of ResultSet according to type and converts to String
254          *   @param inValue  Wert aus ResultSet.
255          *   @param aType  Datenbanktyp.
256          *   @return liefert den Wert als String zurueck. Wenn keine Umwandlung moeglich
257          *           dann /unsupported value/
258          */
259         private String getValueAsString (ResultSet rs, int valueIndex, int aType) throws StorageObjectException {
260                 String outValue = null;
261                 if (rs != null) {
262                         try {
263                                 switch (aType) {
264                                         case java.sql.Types.BIT:
265                                                 outValue = (rs.getBoolean(valueIndex) == true) ? "1" : "0";
266                                                 break;
267                                         case java.sql.Types.INTEGER:case java.sql.Types.SMALLINT:case java.sql.Types.TINYINT:case java.sql.Types.BIGINT:
268                                                 int out = rs.getInt(valueIndex);
269                                                 if (!rs.wasNull())
270                                                         outValue = new Integer(out).toString();
271                                                 break;
272                                         case java.sql.Types.NUMERIC:
273             /** @todo Numeric can be float or double depending upon
274              *  metadata.getScale() / especially with oracle */
275                                                 long outl = rs.getLong(valueIndex);
276                                                 if (!rs.wasNull())
277                                                         outValue = new Long(outl).toString();
278                                                 break;
279                                         case java.sql.Types.REAL:
280                                                 float tempf = rs.getFloat(valueIndex);
281                                                 if (!rs.wasNull()) {
282                                                         tempf *= 10;
283                                                         tempf += 0.5;
284                                                         int tempf_int = (int)tempf;
285                                                         tempf = (float)tempf_int;
286                                                         tempf /= 10;
287                                                         outValue = "" + tempf;
288                                                         outValue = outValue.replace('.', ',');
289                                                 }
290                                                 break;
291                                         case java.sql.Types.DOUBLE:
292                                                 double tempd = rs.getDouble(valueIndex);
293                                                 if (!rs.wasNull()) {
294                                                         tempd *= 10;
295                                                         tempd += 0.5;
296                                                         int tempd_int = (int)tempd;
297                                                         tempd = (double)tempd_int;
298                                                         tempd /= 10;
299                                                         outValue = "" + tempd;
300                                                         outValue = outValue.replace('.', ',');
301                                                 }
302                                                 break;
303                                         case java.sql.Types.CHAR:case java.sql.Types.VARCHAR:case java.sql.Types.LONGVARCHAR:
304                                                 outValue = rs.getString(valueIndex);
305                                                 //if (outValue != null)
306                                                         //outValue = StringUtil.encodeHtml(StringUtil.unquote(outValue));
307                                                 break;
308                                         case java.sql.Types.LONGVARBINARY:
309                                                 outValue = rs.getString(valueIndex);
310                                                 //if (outValue != null)
311                                                 //outValue = StringUtil.encodeHtml(StringUtil.unquote(outValue));
312                                                 break;
313                                         case java.sql.Types.TIMESTAMP:
314             // it's important to use Timestamp here as getting it
315             // as a string is undefined and is only there for debugging
316             // according to the API. we can make it a string through formatting.
317             // -mh
318                                           Timestamp timestamp = (rs.getTimestamp(valueIndex));
319             if(!rs.wasNull()) {
320               java.util.Date date = new java.util.Date(timestamp.getTime());
321               outValue = _dateFormatterOut.format(date);
322               _cal.setTime(date);
323               int offset = _cal.get(Calendar.ZONE_OFFSET)+
324                             _cal.get(Calendar.DST_OFFSET);
325               String tzOffset = StringUtil.zeroPaddingNumber(
326                                                      offset/_millisPerHour,2,2);
327               outValue = outValue+"+"+tzOffset;
328             }
329                                                 break;
330                                         default:
331                                                 outValue = "<unsupported value>";
332                                                 theLog.printWarning("Unsupported Datatype: at " + valueIndex +
333                                                                 " (" + aType + ")");
334                                 }
335                         } catch (SQLException e) {
336                                 throw  new StorageObjectException("Could not get Value out of Resultset -- "
337                                                 + e.toString());
338                         }
339                 }
340                 return  outValue;
341         }
342
343         /*
344          *   select-Operator um einen Datensatz zu bekommen.
345          *   @param id Primaerschluessel des Datensatzes.
346          *   @return liefert EntityObject des gefundenen Datensatzes oder null.
347          */
348         public Entity selectById(String id)     throws StorageObjectException
349   {
350                 if (id==null||id.equals(""))
351                         throw new StorageObjectException("id war null");
352
353     // ask object store for object
354     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {
355       String uniqueId = id;
356       if ( theEntityClass.equals(StorableObjectEntity.class) )
357         uniqueId+="@"+theTable;
358       StoreIdentifier search_sid = new StoreIdentifier(theEntityClass, uniqueId);
359       theLog.printDebugInfo("CACHE: (dbg) looking for sid " + search_sid.toString());
360       Entity hit = (Entity)o_store.use(search_sid);
361       if ( hit!=null ) return hit;
362     }
363
364                 Statement stmt=null;Connection con=getPooledCon();
365                 Entity returnEntity=null;
366                 try {
367                         ResultSet rs;
368                         /** @todo better prepared statement */
369                         String selectSql = "select * from " + theTable + " where " + thePKeyName + "=" + id;
370                         stmt = con.createStatement();
371                         rs = executeSql(stmt, selectSql);
372                         if (rs != null) {
373                                 if (evaluatedMetaData==false) evalMetaData(rs.getMetaData());
374                                 if (rs.next())
375                                         returnEntity = makeEntityFromResultSet(rs);
376                                 else theLog.printDebugInfo("Keine daten fuer id: " + id + "in Tabelle" + theTable);
377                                 rs.close();
378                         }
379                         else {
380                                 theLog.printDebugInfo("No Data for Id " + id + " in Table " + theTable);
381                         }
382                 }
383                 catch (SQLException sqe){
384                         throwSQLException(sqe,"selectById"); return null;
385                 }
386                 catch (NumberFormatException e) {
387                         theLog.printError("ID ist keine Zahl: " + id);
388                 }
389                 finally { freeConnection(con,stmt); }
390
391                 /** @todo OS: Entity should be saved in ostore */
392                 return returnEntity;
393         }
394
395
396         /**
397          *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.
398          *   @param key  Datenbankfeld der Bedingung.
399          *   @param value  Wert die der key anehmen muss.
400          *   @return EntityList mit den gematchten Entities
401          */
402         public EntityList selectByFieldValue(String aField, String aValue)
403                 throws StorageObjectException
404         {
405                 return selectByFieldValue(aField, aValue, 0);
406         }
407
408         /**
409          *   select-Operator um Datensaetze zu bekommen, die key = value erfuellen.
410          *   @param key  Datenbankfeld der Bedingung.
411          *   @param value  Wert die der key anehmen muss.
412          *   @param offset  Gibt an ab welchem Datensatz angezeigt werden soll.
413          *   @return EntityList mit den gematchten Entities
414          */
415         public EntityList selectByFieldValue(String aField, String aValue, int offset)
416                 throws StorageObjectException
417         {
418                 return selectByWhereClause(aField + "=" + aValue, offset);
419         }
420
421
422         /**
423          * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
424          * Also offset wird der erste Datensatz genommen.
425          *
426          * @param wc where-Clause
427          * @return EntityList mit den gematchten Entities
428          * @exception StorageObjectException
429          */
430         public EntityList selectByWhereClause(String where)
431                 throws StorageObjectException
432         {
433                 return selectByWhereClause(where, 0);
434         }
435
436
437         /**
438          * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
439          * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
440          *
441          * @param wc where-Clause
442          * @param offset ab welchem Datensatz.
443          * @return EntityList mit den gematchten Entities
444          * @exception StorageObjectException
445          */
446         public EntityList selectByWhereClause(String whereClause, int offset)
447                 throws StorageObjectException
448         {
449                 return selectByWhereClause(whereClause, null, offset);
450         }
451
452
453         /**
454          * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
455          * Also offset wird der erste Datensatz genommen.
456          * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
457          *
458          * @param wc where-Clause
459          * @param ob orderBy-Clause
460          * @return EntityList mit den gematchten Entities
461          * @exception StorageObjectException
462          */
463
464         public EntityList selectByWhereClause(String where, String order)
465                 throws StorageObjectException {
466                 return selectByWhereClause(where, order, 0);
467         }
468
469
470         /**
471          * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
472          * Als maximale Anzahl wird das Limit auf der Konfiguration genommen.
473          *
474          * @param wc where-Clause
475          * @param ob orderBy-Clause
476          * @param offset ab welchem Datensatz
477          * @return EntityList mit den gematchten Entities
478          * @exception StorageObjectException
479          */
480
481         public EntityList selectByWhereClause(String whereClause, String orderBy, int offset)
482                 throws StorageObjectException {
483                 return selectByWhereClause(whereClause, orderBy, offset, defaultLimit);
484         }
485
486
487         /**
488          * select-Operator liefert eine EntityListe mit den gematchten Datensätzen zurück.
489          * @param wc where-Clause
490          * @param ob orderBy-Clause
491          * @param offset ab welchem Datensatz
492          * @param limit wieviele Datensätze
493          * @return EntityList mit den gematchten Entities
494          * @exception StorageObjectException
495          */
496
497         public EntityList selectByWhereClause(String wc, String ob, int offset, int limit)
498                 throws StorageObjectException
499   {
500
501     // check o_store for entitylist
502     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {
503       StoreIdentifier search_sid =
504         new StoreIdentifier( theEntityClass,
505                              StoreContainerType.STOC_TYPE_ENTITYLIST,
506                              StoreUtil.getEntityListUniqueIdentifierFor(theTable,wc,ob,offset,limit) );
507       EntityList hit = (EntityList)o_store.use(search_sid);
508       if ( hit!=null ) {
509         theLog.printDebugInfo("CACHE (hit): " + search_sid.toString());
510         return hit;
511       }
512     }
513
514                 // local
515                 EntityList    theReturnList=null;
516                 Connection    con=null; Statement stmt=null;
517                 ResultSet     rs;
518                 int           offsetCount = 0, count=0;
519
520                 // build sql-statement
521
522                 /** @todo count sql string should only be assembled if we really count
523                  *  see below at the end of method //rk */
524
525                 if (wc != null && wc.length() == 0) {
526                         wc = null;
527                 }
528                 StringBuffer countSql = new StringBuffer("select count(*) from ").append(theTable);
529                 StringBuffer selectSql = new StringBuffer("select * from ").append(theTable);
530                 if (wc != null) {
531                         selectSql.append(" where ").append(wc);
532                         countSql.append(" where ").append(wc);
533                 }
534                 if (ob != null && !(ob.length() == 0)) {
535                         selectSql.append(" order by ").append(ob);
536                 }
537                 if (theAdaptor.hasLimit()) {
538                         if (limit > -1 && offset > -1) {
539                                 selectSql.append(" limit ");
540                                 if (theAdaptor.reverseLimit()) {
541                                         selectSql.append(limit).append(",").append(offset);
542                                 }
543                                 else {
544                                         selectSql.append(offset).append(",").append(limit);
545                                 }
546                         }
547                 }
548
549                 // execute sql
550                 try {
551                         con = getPooledCon();
552                         stmt = con.createStatement();
553
554                         // selecting...
555                         rs = executeSql(stmt, selectSql.toString());
556                         if (rs != null) {
557                                 if (!evaluatedMetaData) evalMetaData(rs.getMetaData());
558
559                                 theReturnList = new EntityList();
560                                 Entity theResultEntity;
561                                 while (rs.next()) {
562                                         theResultEntity = makeEntityFromResultSet(rs);
563                                         theReturnList.add(theResultEntity);
564                                         offsetCount++;
565                                 }
566                                 rs.close();
567                         }
568
569                         // making entitylist infos
570                         if (!(theAdaptor.hasLimit())) count = offsetCount;
571
572                         if (theReturnList != null) {
573                                 // now we decide if we have to know an overall count...
574                                 count=offsetCount;
575                                 if (limit > -1 && offset > -1) {
576                                         if (offsetCount==limit) {
577                                                 /** @todo counting should be deffered to entitylist
578                                                  *  getSize() should be used */
579                                                 rs = executeSql(stmt, countSql.toString());
580                                                 if (rs != null) {
581                                                         if ( rs.next() ) count = rs.getInt(1);
582                                                         rs.close();
583                                                 }
584                                                 else theLog.printError("Could not count: " + countSql);
585                                         }
586                                 }
587                                 theReturnList.setCount(count);
588                                 theReturnList.setOffset(offset);
589                                 theReturnList.setWhere(wc);
590                                 theReturnList.setOrder(ob);
591         theReturnList.setStorage(this);
592         theReturnList.setLimit(limit);
593                                 if ( offset >= limit )
594                                         theReturnList.setPrevBatch(offset - limit);
595                                 if ( offset+offsetCount < count )
596                                         theReturnList.setNextBatch(offset + limit);
597         if ( StoreUtil.implementsStorableObject(theEntityClass) ) {
598           StoreIdentifier sid=theReturnList.getStoreIdentifier();
599           theLog.printDebugInfo("CACHE (add): " + sid.toString());
600           o_store.add(sid);
601         }
602                         }
603                 }
604                 catch (SQLException sqe) { throwSQLException(sqe, "selectByWhereClause"); }
605                 finally { freeConnection(con, stmt); }
606
607                 return  theReturnList;
608         }
609
610
611         /**
612          *  Bastelt aus einer Zeile der Datenbank ein EntityObjekt.
613          *
614          *  @param rs Das ResultSetObjekt.
615          *  @return Entity Die Entity.
616          */
617         private Entity makeEntityFromResultSet (ResultSet rs)
618                 throws StorageObjectException
619         {
620                 /** @todo OS: get Pkey from ResultSet and consult ObjectStore */
621                 HashMap theResultHash = new HashMap();
622                 String theResult = null;
623                 int theType;
624                 Entity returnEntity = null;
625                 try {
626                         int size = metadataFields.size();
627                         for (int i = 0; i < size; i++) {
628                                 // alle durchlaufen bis nix mehr da
629
630                                 theType = metadataTypes[i];
631                                 if (theType == java.sql.Types.LONGVARBINARY) {
632                                         InputStreamReader is = (InputStreamReader)rs.getCharacterStream(i + 1);
633                                         if (is != null) {
634                                                 char[] data = new char[32768];
635                                                 StringBuffer theResultString = new StringBuffer();
636                                                 int len;
637                                                 while ((len = is.read(data)) > 0) {
638                                                         theResultString.append(data, 0, len);
639                                                 }
640                                                 is.close();
641                                                 theResult = theResultString.toString();
642                                         }
643                                         else {
644                                                 theResult = null;
645                                         }
646                                 }
647                                 else {
648                                         theResult = getValueAsString(rs, (i + 1), theType);
649                                 }
650                                 if (theResult != null) {
651                                         theResultHash.put(metadataFields.get(i), theResult);
652                                 }
653                         }
654       if (theEntityClass != null) {
655         returnEntity = (Entity)theEntityClass.newInstance();
656         returnEntity.setValues(theResultHash);
657         returnEntity.setStorage(myselfDatabase);
658         if ( returnEntity instanceof StorableObject ) {
659           theLog.printDebugInfo("CACHE: ( in) " + returnEntity.getId() + " :"+theTable);
660           o_store.add(((StorableObject)returnEntity).getStoreIdentifier());
661         }
662       } else {
663         throwStorageObjectException("Internal Error: theEntityClass not set!");
664       }
665                 } catch (IllegalAccessException e) {
666                         throwStorageObjectException("Kein Zugriff! -- " + e.toString());
667                 } catch (IOException e) {
668                         throwStorageObjectException("IOException! -- " + e.toString());
669                 } catch (InstantiationException e) {
670                         throwStorageObjectException("Keine Instantiiierung! -- " + e.toString());
671                 } catch (SQLException sqe) {
672                         throwSQLException(sqe, "makeEntityFromResultSet");
673                         return  null;
674                 }
675                 return  returnEntity;
676         }
677
678         /**
679          * insert-Operator: fügt eine Entity in die Tabelle ein. Eine Spalte WEBDB_CREATE
680          * wird automatisch mit dem aktuellen Datum gefuellt.
681          *
682          * @param theEntity
683          * @return der Wert des Primary-keys der eingefügten Entity
684          */
685         public String insert (Entity theEntity) throws StorageObjectException {
686                 //cache
687                 invalidatePopupCache();
688
689     // invalidating all EntityLists corresponding with theEntityClass
690     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {
691       StoreContainerType stoc_type =
692         StoreContainerType.valueOf( theEntityClass,
693                                     StoreContainerType.STOC_TYPE_ENTITYLIST);
694       o_store.invalidate(stoc_type);
695     }
696
697                 String returnId = null;
698                 Connection con = null; PreparedStatement pstmt = null;
699
700     try {
701                         ArrayList streamedInput = theEntity.streamedInput();
702                         StringBuffer f = new StringBuffer();
703                         StringBuffer v = new StringBuffer();
704                         String aField, aValue;
705                         boolean firstField = true;
706                         // make sql-string
707                         for (int i = 0; i < getFields().size(); i++) {
708                                 aField = (String)getFields().get(i);
709                                 if (!aField.equals(thePKeyName)) {
710                                         aValue = null;
711                                         // sonderfaelle
712                                         if (aField.equals("webdb_create") ||
713               aField.equals("webdb_lastchange")) {
714                                                 aValue = "NOW()";
715                                         }
716                                         else {
717                                                 if (streamedInput != null && streamedInput.contains(aField)) {
718                                                         aValue = "?";
719                                                 }
720                                                 else {
721                                                         if (theEntity.hasValueForField(aField)) {
722                                                                 aValue = "'" + StringUtil.quote((String)theEntity.getValue(aField))
723                                                                                 + "'";
724                                                         }
725                                                 }
726                                         }
727                                         // wenn Wert gegeben, dann einbauen
728                                         if (aValue != null) {
729                                                 if (firstField == false) {
730                                                         f.append(",");
731                                                         v.append(",");
732                                                 }
733                                                 else {
734                                                         firstField = false;
735                                                 }
736                                                 f.append(aField);
737                                                 v.append(aValue);
738                                         }
739                                 }
740                         }         // end for
741                         // insert into db
742                         StringBuffer sqlBuf = new StringBuffer("insert into ").append(theTable).append("(").append(f).append(") values (").append(v).append(")");
743                         String sql = sqlBuf.toString();
744                         theLog.printInfo("INSERT: " + sql);
745                         con = getPooledCon();
746                         con.setAutoCommit(false);
747                         pstmt = con.prepareStatement(sql);
748                         if (streamedInput != null) {
749                                 for (int i = 0; i < streamedInput.size(); i++) {
750                                         String inputString = (String)theEntity.getValue((String)streamedInput.get(i));
751                                         pstmt.setBytes(i + 1, inputString.getBytes());
752                                 }
753                         }
754                         int ret = pstmt.executeUpdate();
755                         if(ret == 0){
756                                 //insert failed
757                                 return null;
758                         }
759                         pstmt = con.prepareStatement(theAdaptor.getLastInsertSQL((Database)myselfDatabase));
760                         ResultSet rs = pstmt.executeQuery();
761                         rs.next();
762                         returnId = rs.getString(1);
763                         theEntity.setId(returnId);
764                 } catch (SQLException sqe) {
765                         throwSQLException(sqe, "insert");
766                 } finally {
767                         try {
768                                 con.setAutoCommit(true);
769                         } catch (Exception e) {
770                                 ;
771                         }
772                         freeConnection(con, pstmt);
773                 }
774     /** @todo store entity in o_store */
775                 return  returnId;
776         }
777
778         /**
779          * update-Operator: aktualisiert eine Entity. Eine Spalte WEBDB_LASTCHANGE
780          * wird automatisch mit dem aktuellen Datum gefuellt.
781          *
782          * @param theEntity
783          */
784         public void update (Entity theEntity) throws StorageObjectException
785   {
786                 Connection con = null; PreparedStatement pstmt = null;
787                 /** @todo this is stupid: why do we prepare statement, when we
788                  *  throw it away afterwards. should be regular statement
789                  *  update/insert could better be one routine called save()
790                  *  that chooses to either insert or update depending if we
791                  *  have a primary key in the entity. i don't know if we
792                  *  still need the streamed input fields. // rk  */
793
794                 /** @todo extension: check if Entity did change, otherwise we don't need
795      *  the roundtrip to the database */
796
797                 /** invalidating corresponding entitylists in o_store*/
798     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {
799       StoreContainerType stoc_type =
800         StoreContainerType.valueOf( theEntityClass,
801                                     StoreContainerType.STOC_TYPE_ENTITYLIST);
802       o_store.invalidate(stoc_type);
803     }
804
805                 ArrayList streamedInput = theEntity.streamedInput();
806                 String id = theEntity.getId();
807                 String aField;
808                 StringBuffer fv = new StringBuffer();
809                 boolean firstField = true;
810                 //cache
811                 invalidatePopupCache();
812                 // build sql statement
813                 for (int i = 0; i < getFields().size(); i++) {
814                         aField = (String)metadataFields.get(i);
815                         // only normal cases
816                         if (!(aField.equals(thePKeyName) || aField.equals("webdb_create") ||
817                                         aField.equals("webdb_lastchange") || (streamedInput != null && streamedInput.contains(aField)))) {
818                                 if (theEntity.hasValueForField(aField)) {
819                                         if (firstField == false) {
820                                                 fv.append(", ");
821                                         }
822                                         else {
823                                                 firstField = false;
824                                         }
825                                         fv.append(aField).append("='").append(StringUtil.quote((String)theEntity.getValue(aField))).append("'");
826                                 }
827                         }
828                 }
829                 StringBuffer sql = new StringBuffer("update ").append(theTable).append(" set ").append(fv);
830                 // exceptions
831                 if (metadataFields.contains("webdb_lastchange")) {
832                         sql.append(",webdb_lastchange=NOW()");
833                 }
834     // special case: the webdb_create requires the field in yyyy-mm-dd HH:mm
835     // format so anything extra will be ignored. -mh
836                 if (metadataFields.contains("webdb_create") &&
837         theEntity.hasValueForField("webdb_create")) {
838       // minimum of 10 (yyyy-mm-dd)...
839       if (theEntity.getValue("webdb_create").length() >= 10) {
840         String dateString = theEntity.getValue("webdb_create");
841         // if only 10, then add 00:00 so it doesn't throw a ParseException
842         if (dateString.length() == 10)
843           dateString=dateString+" 00:00";
844
845         // TimeStamp stuff
846         try {
847           java.util.Date d = _dateFormatterIn.parse(dateString);
848           Timestamp tStamp = new Timestamp(d.getTime());
849           sql.append(",webdb_create='"+tStamp.toString()+"'");
850         } catch (ParseException e) {
851           throw new StorageObjectException(e.toString());
852         }
853       }
854                 }
855                 if (streamedInput != null) {
856                         for (int i = 0; i < streamedInput.size(); i++) {
857                                 sql.append(",").append(streamedInput.get(i)).append("=?");
858                         }
859                 }
860                 sql.append(" where id=").append(id);
861                 theLog.printInfo("UPDATE: " + sql);
862                 // execute sql
863                 try {
864                         con = getPooledCon();
865                         con.setAutoCommit(false);
866                         pstmt = con.prepareStatement(sql.toString());
867                         if (streamedInput != null) {
868                                 for (int i = 0; i < streamedInput.size(); i++) {
869                                         String inputString = theEntity.getValue((String)streamedInput.get(i));
870                                         pstmt.setBytes(i + 1, inputString.getBytes());
871                                 }
872                         }
873                         pstmt.executeUpdate();
874                 } catch (SQLException sqe) {
875                         throwSQLException(sqe, "update");
876                 } finally {
877                         try {
878                                 con.setAutoCommit(true);
879                         } catch (Exception e) {
880                                 ;
881                         }
882                         freeConnection(con, pstmt);
883                 }
884         }
885
886         /*
887          *   delete-Operator
888          *   @param id des zu loeschenden Datensatzes
889          *   @return boolean liefert true zurueck, wenn loeschen erfolgreich war.
890          */
891         public boolean delete (String id) throws StorageObjectException {
892
893                 invalidatePopupCache();
894     // ostore send notification
895     if ( StoreUtil.implementsStorableObject(theEntityClass) ) {
896       String uniqueId = id;
897       if ( theEntityClass.equals(StorableObjectEntity.class) )
898         uniqueId+="@"+theTable;
899                         theLog.printInfo("CACHE: (del) " + id);
900                         StoreIdentifier search_sid =
901         new StoreIdentifier(theEntityClass, StoreContainerType.STOC_TYPE_ENTITY, uniqueId);
902       o_store.invalidate(search_sid);
903                 }
904
905                 /** @todo could be prepared Statement */
906                 Statement stmt = null; Connection con = null;
907                 int res = 0;
908                 String sql="delete from "+theTable+" where "+thePKeyName+"='"+id+"'";
909                 theLog.printInfo("DELETE " + sql);
910                 try {
911                         con = getPooledCon(); stmt = con.createStatement();
912                         res = stmt.executeUpdate(sql);
913                 }
914     catch (SQLException sqe) { throwSQLException(sqe, "delete"); }
915     finally { freeConnection(con, stmt); }
916
917                 return  (res > 0) ? true : false;
918         }
919
920         /* noch nicht implementiert.
921          * @return immer false
922          */
923         public boolean delete (EntityList theEntityList) {
924                 invalidatePopupCache();
925                 return  false;
926         }
927
928         /**
929          * Diese Methode sollte ueberschrieben werden, wenn fuer die abgeleitete Database-Klasse
930          * eine SimpleList mit Standard-Popupdaten erzeugt werden koennen soll.
931          * @return null
932          */
933         public SimpleList getPopupData () throws StorageObjectException {
934                 return  null;
935         }
936
937         /**
938          *  Holt Daten fuer Popups.
939          *  @param name  Name des Feldes.
940          *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.
941          *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.
942          */
943         public SimpleList getPopupData (String name, boolean hasNullValue)
944                 throws StorageObjectException {
945                 return  getPopupData(name, hasNullValue, null);
946         }
947
948         /**
949          *  Holt Daten fuer Popups.
950          *  @param name  Name des Feldes.
951          *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.
952          *  @param where  Schraenkt die Selektion der Datensaetze ein.
953          *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.
954          */
955         public SimpleList getPopupData (String name, boolean hasNullValue, String where) throws StorageObjectException {
956          return  getPopupData(name, hasNullValue, where, null);
957         }
958
959         /**
960          *  Holt Daten fuer Popups.
961          *  @param name  Name des Feldes.
962          *  @param hasNullValue  Wenn true wird eine leerer  Eintrag fuer die Popups erzeugt.
963          *  @param where  Schraenkt die Selektion der Datensaetze ein.
964          *  @param order  Gibt ein Feld als Sortierkriterium an.
965          *  @return SimpleList Gibt freemarker.template.SimpleList zurueck.
966          */
967         public SimpleList getPopupData (String name, boolean hasNullValue, String where, String order) throws StorageObjectException {
968                 // caching
969                 if (hasPopupCache && popupCache != null)
970                         return  popupCache;
971                 SimpleList simpleList = null;
972                 Connection con = null;
973                 Statement stmt = null;
974                 // build sql
975                 StringBuffer sql = new StringBuffer("select ").append(thePKeyName)
976                                                                                                                                                                 .append(",").append(name).append(" from ")
977                                                                                                                                                                 .append(theTable);
978                 if (where != null && !(where.length() == 0))
979                         sql.append(" where ").append(where);
980                 sql.append(" order by ");
981                 if (order != null && !(order.length() == 0))
982                         sql.append(order);
983                 else
984                         sql.append(name);
985                 // execute sql
986                 try {
987                         con = getPooledCon();
988                 } catch (Exception e) {
989                         throw new StorageObjectException(e.toString());
990                 }
991                 try {
992                         stmt = con.createStatement();
993                         ResultSet rs = executeSql(stmt, sql.toString());
994
995                         if (rs != null) {
996                                 if (!evaluatedMetaData) get_meta_data();
997                                 simpleList = new SimpleList();
998                                 // if popup has null-selector
999                                 if (hasNullValue) simpleList.add(POPUP_EMTYLINE);
1000
1001                                 SimpleHash popupDict;
1002                                 while (rs.next()) {
1003                                         popupDict = new SimpleHash();
1004                                         popupDict.put("key", getValueAsString(rs, 1, thePKeyType));
1005                                         popupDict.put("value", rs.getString(2));
1006                                         simpleList.add(popupDict);
1007                                 }
1008                                 rs.close();
1009                         }
1010                 } catch (Exception e) {
1011                         theLog.printError("getPopupData: "+e.toString());
1012                         throw new StorageObjectException(e.toString());
1013                 } finally {
1014                         freeConnection(con, stmt);
1015                 }
1016
1017                 if (hasPopupCache) popupCache = simpleList;
1018                 return  simpleList;
1019         }
1020
1021         /**
1022          * Liefert alle Daten der Tabelle als SimpleHash zurueck. Dies wird verwandt,
1023          * wenn in den Templates ein Lookup-Table benoetigt wird. Sollte nur bei kleinen
1024          * Tabellen Verwendung finden.
1025          * @return SimpleHash mit den Tabellezeilen.
1026          */
1027         public SimpleHash getHashData () {
1028                 /** @todo dangerous! this should have a flag to be enabled, otherwise
1029                  *  very big Hashes could be returned */
1030                 if (hashCache == null) {
1031                         try {
1032                                 hashCache = HTMLTemplateProcessor.makeSimpleHash(selectByWhereClause("",
1033                                                 -1));
1034                         } catch (StorageObjectException e) {
1035                                 theLog.printDebugInfo(e.toString());
1036                         }
1037                 }
1038                 return  hashCache;
1039         }
1040
1041         /* invalidates the popupCache
1042          */
1043         protected void invalidatePopupCache () {
1044                 /** @todo  invalidates toooo much */
1045                 popupCache = null;
1046                 hashCache = null;
1047         }
1048
1049         /**
1050          * Diese Methode fuehrt den Sqlstring <i>sql</i> aus und timed im Logfile.
1051          * @param stmt Statemnt
1052          * @param sql Sql-String
1053          * @return ResultSet
1054          * @exception StorageObjectException
1055          */
1056         public ResultSet executeSql (Statement stmt, String sql)
1057                 throws StorageObjectException, SQLException
1058         {
1059                 long startTime = System.currentTimeMillis();
1060                 ResultSet rs;
1061                 try {
1062                         rs = stmt.executeQuery(sql);
1063                         theLog.printInfo((System.currentTimeMillis() - startTime) + "ms. for: "
1064                                 + sql);
1065                 }
1066                 catch (SQLException e)
1067                 {
1068                         theLog.printDebugInfo("Failed: " + (System.currentTimeMillis()
1069                                                                                                                 - startTime) + "ms. for: "+ sql);
1070                         throw e;
1071                 }
1072
1073                 return  rs;
1074         }
1075
1076         /**
1077          * Fuehrt Statement stmt aus und liefert Resultset zurueck. Das SQL-Statment wird
1078          * getimed und geloggt.
1079          * @param stmt PreparedStatement mit der SQL-Anweisung
1080          * @return Liefert ResultSet des Statements zurueck.
1081          * @exception StorageObjectException, SQLException
1082          */
1083         public ResultSet executeSql (PreparedStatement stmt)
1084                 throws StorageObjectException, SQLException {
1085
1086                 long startTime = (new java.util.Date()).getTime();
1087                 ResultSet rs = stmt.executeQuery();
1088                 theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms.");
1089                 return  rs;
1090         }
1091
1092                 /**
1093          * returns the number of rows in the table
1094          */
1095         public int getSize(String where)
1096                 throws SQLException,StorageObjectException
1097         {
1098                 long  startTime = System.currentTimeMillis();
1099                 String sql = "SELECT Count(*) FROM "+ theTable;
1100                 if (where != null && !(where.length() == 0))
1101                   sql = sql + " where " + where;
1102                 Connection con = null;
1103                 Statement stmt = null;
1104                 int result = 0;
1105
1106                 try {
1107                         con = getPooledCon();
1108                         stmt = con.createStatement();
1109                         ResultSet rs = executeSql(stmt,sql);
1110                         while(rs.next()){
1111                                 result = rs.getInt(1);
1112                         }
1113                 } catch (SQLException e) {
1114                         theLog.printError(e.toString());
1115                 } finally {
1116                         freeConnection(con,stmt);
1117                 }
1118                 //theLog.printInfo(theTable + " has "+ result +" rows where " + where);
1119                 theLog.printInfo((System.currentTimeMillis() - startTime) + "ms. for: "
1120                                                                                 + sql);
1121                 return result;
1122         }
1123
1124         public int executeUpdate(Statement stmt, String sql)
1125                 throws StorageObjectException, SQLException
1126         {
1127                 int rs;
1128                 long  startTime = (new java.util.Date()).getTime();
1129                 try
1130                 {
1131                         rs = stmt.executeUpdate(sql);
1132                         theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: "
1133                                                                                                 + sql);
1134                 }
1135                 catch (SQLException e)
1136                 {
1137                         theLog.printDebugInfo("Failed: " + (new java.util.Date().getTime()
1138                                                                                                                 - startTime) + "ms. for: "+ sql);
1139                         throw e;
1140                 }
1141                 return rs;
1142         }
1143
1144         public int executeUpdate(String sql)
1145                 throws StorageObjectException, SQLException
1146         {
1147                 int result=-1;
1148                 long  startTime = (new java.util.Date()).getTime();
1149                 Connection con=null;PreparedStatement pstmt=null;
1150                 try {
1151                         con=getPooledCon();
1152                         pstmt = con.prepareStatement(sql);
1153                         result = pstmt.executeUpdate();
1154                 }
1155                 catch (Exception e) {
1156                         theLog.printDebugInfo("settimage :: setImage gescheitert: "+e.toString());
1157                         throw new StorageObjectException("executeUpdate failed: "+e.toString());
1158                 }
1159                 finally { freeConnection(con,pstmt); }
1160                 theLog.printInfo((new java.util.Date().getTime() - startTime) + "ms. for: "
1161                                                                                 + sql);
1162                 return result;
1163         }
1164
1165         /**
1166          * Wertet ResultSetMetaData aus und setzt interne Daten entsprechend
1167          * @param md ResultSetMetaData
1168          * @exception StorageObjectException
1169          */
1170         private void evalMetaData (ResultSetMetaData md)
1171                 throws StorageObjectException {
1172
1173                 this.evaluatedMetaData = true;
1174                 this.metadataFields = new ArrayList();
1175                 this.metadataLabels = new ArrayList();
1176                 this.metadataNotNullFields = new ArrayList();
1177                 try {
1178                         int numFields = md.getColumnCount();
1179                         this.metadataTypes = new int[numFields];
1180                         String aField;
1181                         int aType;
1182                         for (int i = 1; i <= numFields; i++) {
1183                                 aField = md.getColumnName(i);
1184                                 metadataFields.add(aField);
1185                                 metadataLabels.add(md.getColumnLabel(i));
1186                                 aType = md.getColumnType(i);
1187                                 metadataTypes[i - 1] = aType;
1188                                 if (aField.equals(thePKeyName)) {
1189                                         thePKeyType = aType; thePKeyIndex = i;
1190                                 }
1191                                 if (md.isNullable(i) == md.columnNullable) {
1192                                         metadataNotNullFields.add(aField);
1193                                 }
1194                         }
1195                 } catch (SQLException e) {
1196                         throwSQLException(e, "evalMetaData");
1197                 }
1198         }
1199
1200         /**
1201          *  Wertet die Metadaten eines Resultsets fuer eine Tabelle aus,
1202          *  um die alle Columns und Typen einer Tabelle zu ermitteln.
1203          */
1204         private void get_meta_data () throws StorageObjectException {
1205                 Connection con = null;
1206                 PreparedStatement pstmt = null;
1207                 String sql = "select * from " + theTable + " where 0=1";
1208                 try {
1209                         con = getPooledCon();
1210                         pstmt = con.prepareStatement(sql);
1211                         theLog.printInfo("METADATA: " + sql);
1212                         ResultSet rs = pstmt.executeQuery();
1213                         evalMetaData(rs.getMetaData());
1214                         rs.close();
1215                 } catch (SQLException e) {
1216                         throwSQLException(e, "get_meta_data");
1217                 } finally {
1218                         freeConnection(con, pstmt);
1219                 }
1220         }
1221
1222
1223         public Connection getPooledCon() throws StorageObjectException {
1224                 /* @todo , doublecheck but I'm pretty sure that this is unnecessary. -mh
1225                         try{
1226                         Class.forName("com.codestudio.sql.PoolMan").newInstance();
1227                 } catch (Exception e){
1228                         throw new StorageObjectException("Could not find the PoolMan Driver"
1229                                                                                                                                                                 +e.toString());
1230                 }*/
1231                 Connection con = null;
1232                 try{
1233                         con = SQLManager.getInstance().requestConnection();
1234                 } catch(SQLException e){
1235                         theLog.printError("could not connect to the database "+e.toString());
1236                         System.err.println("could not connect to the database "+e.toString());
1237                         throw new StorageObjectException("Could not connect to the database"+
1238                                                                                                                                                                 e.toString());
1239                 }
1240                 return con;
1241         }
1242
1243         public void freeConnection (Connection con, Statement stmt)
1244                 throws StorageObjectException {
1245                 SQLManager.getInstance().closeStatement(stmt);
1246                 SQLManager.getInstance().returnConnection(con);
1247         }
1248
1249         /**
1250          * Wertet SQLException aus und wirft dannach eine StorageObjectException
1251          * @param sqe SQLException
1252          * @param wo Funktonsname, in der die SQLException geworfen wurde
1253          * @exception StorageObjectException
1254          */
1255         protected void throwSQLException (SQLException sqe, String wo)
1256                 throws StorageObjectException {
1257                 String state = "";
1258                 String message = "";
1259                 int vendor = 0;
1260                 if (sqe != null) {
1261                         state = sqe.getSQLState();
1262                         message = sqe.getMessage();
1263                         vendor = sqe.getErrorCode();
1264                 }
1265                 theLog.printError(state + ": " + vendor + " : " + message + " Funktion: "
1266                                 + wo);
1267                 throw  new StorageObjectException((sqe == null) ? "undefined sql exception" :
1268                                 sqe.toString());
1269         }
1270
1271         protected void _throwStorageObjectException (Exception e, String wo)
1272                 throws StorageObjectException {
1273                 if (e != null) {
1274                                 theLog.printError(e.toString()+ wo);
1275                                 throw  new StorageObjectException(wo + e.toString());
1276                 } else {
1277                                 theLog.printError(wo);
1278                                 throw  new StorageObjectException(wo);
1279                 }
1280
1281         }
1282
1283         /**
1284          * Loggt Fehlermeldung mit dem Parameter Message und wirft dannach
1285          * eine StorageObjectException
1286          * @param message Nachricht mit dem Fehler
1287          * @exception StorageObjectException
1288          */
1289         void throwStorageObjectException (String message)
1290                 throws StorageObjectException {
1291                 _throwStorageObjectException(null, message);
1292         }
1293
1294 }
1295
1296
1297