KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > ejb > plugins > cmp > jdbc > metadata > JDBCEntityMetaData


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.ejb.plugins.cmp.jdbc.metadata;
23
24 import java.util.ArrayList JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.lang.reflect.Method JavaDoc;
32
33
34 import org.jboss.deployment.DeploymentException;
35 import org.jboss.metadata.EntityMetaData;
36 import org.jboss.metadata.MetaData;
37 import org.jboss.metadata.QueryMetaData;
38 import org.jboss.mx.util.MBeanServerLocator;
39 import org.w3c.dom.Element JavaDoc;
40
41 import javax.management.ObjectName JavaDoc;
42 import javax.management.MalformedObjectNameException JavaDoc;
43 import javax.management.MBeanServer JavaDoc;
44
45 /**
46  * This immutable class contains information about an entity
47  *
48  * @author <a HREF="mailto:dain@daingroup.com">Dain Sundstrom</a>
49  * @author <a HREF="sebastien.alborini@m4x.org">Sebastien Alborini</a>
50  * @author <a HREF="mailto:dirk@jboss.de">Dirk Zimmermann</a>
51  * @author <a HREF="mailto:loubyansky@hotmail.com">Alex Loubyansky</a>
52  * @author <a HREF="mailto:heiko.rupp@cellent.de">Heiko W. Rupp</a>
53  * @version $Revision: 37459 $
54  */

55 public final class JDBCEntityMetaData
56 {
57    /**
58     * application metadata in which this entity is defined
59     */

60    private final JDBCApplicationMetaData jdbcApplication;
61
62    /**
63     * data source name in jndi
64     */

65    private final String JavaDoc dataSourceName;
66
67    /**
68     * type mapping name as specified in the deployment descriptor
69     */

70    private final String JavaDoc datasourceMappingName;
71
72    /**
73     * type mapping used for this entity
74     */

75    private final JDBCTypeMappingMetaData datasourceMapping;
76
77    /**
78     * the name of this entity
79     */

80    private final String JavaDoc entityName;
81
82    /**
83     * the abstract schema name of this entity
84     */

85    private final String JavaDoc abstractSchemaName;
86
87    /**
88     * the implementation class of this entity
89     */

90    private final Class JavaDoc entityClass;
91
92    /**
93     * the home class of this entity
94     */

95    private final Class JavaDoc homeClass;
96
97    /**
98     * the remote class of this entity
99     */

100    private final Class JavaDoc remoteClass;
101
102    /**
103     * the local home class of this entity
104     */

105    private final Class JavaDoc localHomeClass;
106
107    /**
108     * the local class of this entity
109     */

110    private final Class JavaDoc localClass;
111
112    /**
113     * Does this entity use cmp 1.x?
114     */

115    private final boolean isCMP1x;
116
117    /**
118     * the name of the table to which this entity is persisted
119     */

120    private final String JavaDoc tableName;
121
122    /**
123     * Should we try and create the table when deployed?
124     */

125    private final boolean createTable;
126
127    /**
128     * Should we drop the table when undeployed?
129     */

130    private final boolean removeTable;
131
132    /**
133     * Should we alter the table when deployed?
134     */

135    private final boolean alterTable;
136
137
138    /**
139     * What command should be issued directly after creation
140     * of a table?
141     */

142    private final ArrayList JavaDoc tablePostCreateCmd;
143
144    /**
145     * Should we use 'SELECT ... FOR UPDATE' syntax when loading?
146     */

147    private final boolean rowLocking;
148
149    /**
150     * Is this entity read-only?
151     */

152    private final boolean readOnly;
153
154    /**
155     * how long is a read valid
156     */

157    private final int readTimeOut;
158
159    /**
160     * Should the table have a primary key constraint?
161     */

162    private final boolean primaryKeyConstraint;
163
164    /**
165     * the java class of the primary key
166     */

167    private final Class JavaDoc primaryKeyClass;
168
169    /**
170     * the name of the primary key field or null if the primary key field
171     * is multivalued
172     */

173    private final String JavaDoc primaryKeyFieldName;
174
175    /**
176     * Map of the cmp fields of this entity by field name.
177     */

178    private final Map JavaDoc cmpFieldsByName = new HashMap JavaDoc();
179    private final List JavaDoc cmpFields = new ArrayList JavaDoc();
180
181    /**
182     * A map of all the load groups by name.
183     */

184    private final Map JavaDoc loadGroups = new HashMap JavaDoc();
185
186    /**
187     * The fields which should always be loaded when an entity of this type
188     * is loaded.
189     */

190    private final String JavaDoc eagerLoadGroup;
191
192    /**
193     * A list of groups (also lists) of the fields that should be lazy
194     * loaded together.
195     */

196    private final List JavaDoc lazyLoadGroups = new ArrayList JavaDoc();
197
198    /**
199     * Map of the queries on this entity by the Method that invokes the query.
200     */

201    private final Map JavaDoc queries = new HashMap JavaDoc();
202
203    /**
204     * The factory used to used to create query meta data
205     */

206    private final JDBCQueryMetaDataFactory queryFactory;
207
208    /**
209     * The read ahead meta data
210     */

211    private final JDBCReadAheadMetaData readAhead;
212
213    /**
214     * clean-read-ahead-on-load
215     * Since 3.2.5RC1, previously read ahead cache was cleaned after loading.
216     */

217    private final boolean cleanReadAheadOnLoad;
218
219    /**
220     * The maximum number of read ahead lists that can be tracked for this
221     * entity.
222     */

223    private final int listCacheMax;
224
225    /**
226     * The number of entities to read in one round-trip to the
227     * underlying data store.
228     */

229    private final int fetchSize;
230
231    /**
232     * entity command meta data
233     */

234    private final JDBCEntityCommandMetaData entityCommand;
235
236
237    /**
238     * optimistic locking metadata
239     */

240
241    private final JDBCOptimisticLockingMetaData optimisticLocking;
242
243
244    /**
245     * audit metadata
246     */

247
248    private final JDBCAuditMetaData audit;
249
250    private final Class JavaDoc qlCompiler;
251
252    /**
253     * throw runtime exception metadata
254     */

255    private final boolean throwRuntimeExceptions;
256
257
258    /**
259     * Constructs jdbc entity meta data defined in the jdbcApplication and
260     * with the data from the entity meta data which is loaded from the
261     * ejb-jar.xml file.
262     *
263     * @param jdbcApplication the application in which this entity is defined
264     * @param entity the entity meta data for this entity that is loaded
265     * from the ejb-jar.xml file
266     * @throws DeploymentException if an problem occures while loading the
267     * classes or if data in the ejb-jar.xml is inconsistent with data
268     * from jbosscmp-jdbc.xml file
269     */

270    public JDBCEntityMetaData(JDBCApplicationMetaData jdbcApplication,
271                              EntityMetaData entity)
272       throws DeploymentException
273    {
274       this.jdbcApplication = jdbcApplication;
275       entityName = entity.getEjbName();
276       listCacheMax = 1000;
277       fetchSize = 0;
278
279       try
280       {
281          entityClass = getClassLoader().loadClass(entity.getEjbClass());
282       }
283       catch(ClassNotFoundException JavaDoc e)
284       {
285          throw new DeploymentException("entity class not found: " + entityName);
286       }
287
288       try
289       {
290          primaryKeyClass = getClassLoader().loadClass(entity.getPrimaryKeyClass());
291       }
292       catch(ClassNotFoundException JavaDoc e)
293       {
294          throw new DeploymentException(
295             "could not load primary key class: " +
296             entity.getPrimaryKeyClass()
297          );
298       }
299
300       isCMP1x = entity.isCMP1x();
301       if(isCMP1x)
302       {
303          abstractSchemaName = (entity.getAbstractSchemaName() == null ? entityName : entity.getAbstractSchemaName());
304       }
305       else
306       {
307          abstractSchemaName = entity.getAbstractSchemaName();
308       }
309
310       primaryKeyFieldName = entity.getPrimKeyField();
311
312       String JavaDoc home = entity.getHome();
313       if(home != null)
314       {
315          try
316          {
317             homeClass = getClassLoader().loadClass(home);
318          }
319          catch(ClassNotFoundException JavaDoc e)
320          {
321             throw new DeploymentException("home class not found: " + home);
322          }
323          try
324          {
325             remoteClass = getClassLoader().loadClass(entity.getRemote());
326          }
327          catch(ClassNotFoundException JavaDoc e)
328          {
329             throw new DeploymentException(
330                "remote class not found: " +
331                entity.getRemote()
332             );
333          }
334       }
335       else
336       {
337          homeClass = null;
338          remoteClass = null;
339       }
340
341       String JavaDoc localHome = entity.getLocalHome();
342       if(localHome != null)
343       {
344          try
345          {
346             localHomeClass = getClassLoader().loadClass(localHome);
347          }
348          catch(ClassNotFoundException JavaDoc e)
349          {
350             throw new DeploymentException(
351                "local home class not found: " +
352                localHome
353             );
354          }
355          try
356          {
357             localClass = getClassLoader().loadClass(entity.getLocal());
358          }
359          catch(ClassNotFoundException JavaDoc e)
360          {
361             throw new DeploymentException(
362                "local class not found: " +
363                entity.getLocal()
364             );
365          }
366       }
367       else
368       {
369          // we must have a home or local home
370
if(home == null)
371          {
372             throw new DeploymentException(
373                "Entity must have atleast a home " +
374                "or local home: " + entityName
375             );
376          }
377
378          localHomeClass = null;
379          localClass = null;
380       }
381
382       // we replace the . by _ because some dbs die on it...
383
// the table name may be overridden in importXml(jbosscmp-jdbc.xml)
384
tableName = entityName.replace('.', '_');
385
386       // Warn: readTimeOut should be setup before cmp fields are created
387
// otherwise readTimeOut in cmp fields will be set to 0 by default
388
dataSourceName = null;
389       datasourceMappingName = null;
390       datasourceMapping = null;
391       createTable = false;
392       removeTable = false;
393       alterTable = false;
394       rowLocking = false;
395       primaryKeyConstraint = false;
396       readOnly = false;
397       readTimeOut = -1;
398       tablePostCreateCmd = null;
399       qlCompiler = null;
400       throwRuntimeExceptions = false;
401
402       // build the metadata for the cmp fields now in case there is
403
// no jbosscmp-jdbc.xml
404
List JavaDoc nonPkFieldNames = new ArrayList JavaDoc();
405       for(Iterator JavaDoc i = entity.getCMPFields(); i.hasNext();)
406       {
407          String JavaDoc cmpFieldName = (String JavaDoc) i.next();
408          JDBCCMPFieldMetaData cmpField = new JDBCCMPFieldMetaData(this, cmpFieldName);
409          cmpFields.add(cmpField);
410          cmpFieldsByName.put(cmpFieldName, cmpField);
411          if(!cmpField.isPrimaryKeyMember())
412          {
413             nonPkFieldNames.add(cmpFieldName);
414          }
415       }
416
417       // AL: add unknown primary key if primaryKeyClass is Object
418
// AL: this is set up only in this constructor
419
// AL: because, AFAIK, others are called with default value
420
// AL: produced by this one
421
if(primaryKeyClass == java.lang.Object JavaDoc.class)
422       {
423          JDBCCMPFieldMetaData upkField = new JDBCCMPFieldMetaData(this);
424          cmpFields.add(upkField);
425          cmpFieldsByName.put(upkField.getFieldName(), upkField);
426       }
427
428       // set eager load fields to all group.
429
eagerLoadGroup = "*";
430
431       // Create no lazy load groups. By default every thing is eager loaded.
432
// build the metadata for the queries now in case there is no
433
// jbosscmp-jdbc.xml
434
queryFactory = new JDBCQueryMetaDataFactory(this);
435
436       for(Iterator JavaDoc queriesIterator = entity.getQueries(); queriesIterator.hasNext();)
437       {
438          QueryMetaData queryData = (QueryMetaData) queriesIterator.next();
439          Map JavaDoc newQueries = queryFactory.createJDBCQueryMetaData(queryData);
440          // overrides defaults added above
441
queries.putAll(newQueries);
442       }
443
444       // Create no relationship roles for this entity, will be added
445
// by the relation meta data
446

447       readAhead = JDBCReadAheadMetaData.DEFAULT;
448       cleanReadAheadOnLoad = false;
449       entityCommand = null;
450       optimisticLocking = null;
451       audit = null;
452    }
453
454    /**
455     * Constructs entity meta data with the data contained in the entity xml
456     * element from a jbosscmp-jdbc xml file. Optional values of the xml element
457     * that are not present are loaded from the defalutValues parameter.
458     *
459     * @param jdbcApplication the application in which this entity is defined
460     * @param element the xml Element which contains the metadata about
461     * this entity
462     * @param defaultValues the JDBCEntityMetaData which contains the values
463     * for optional elements of the element
464     * @throws DeploymentException if the xml element is not semantically correct
465     */

466    public JDBCEntityMetaData(JDBCApplicationMetaData jdbcApplication,
467                              Element JavaDoc element,
468                              JDBCEntityMetaData defaultValues)
469       throws DeploymentException
470    {
471       // store passed in application... application in defaultValues may
472
// be different because jdbcApplication is imutable
473
this.jdbcApplication = jdbcApplication;
474
475       // set default values
476
entityName = defaultValues.getName();
477       entityClass = defaultValues.getEntityClass();
478       primaryKeyClass = defaultValues.getPrimaryKeyClass();
479       isCMP1x = defaultValues.isCMP1x;
480       primaryKeyFieldName = defaultValues.getPrimaryKeyFieldName();
481       homeClass = defaultValues.getHomeClass();
482       remoteClass = defaultValues.getRemoteClass();
483       localHomeClass = defaultValues.getLocalHomeClass();
484       localClass = defaultValues.getLocalClass();
485       queryFactory = new JDBCQueryMetaDataFactory(this);
486
487       if(isCMP1x)
488       {
489          abstractSchemaName = (defaultValues.getAbstractSchemaName() == null ?
490             entityName : defaultValues.getAbstractSchemaName());
491       }
492       else
493       {
494          abstractSchemaName = defaultValues.getAbstractSchemaName();
495       }
496
497       // datasource name
498
String JavaDoc dataSourceNameString = MetaData.getOptionalChildContent(element, "datasource");
499       if(dataSourceNameString != null)
500       {
501          dataSourceName = dataSourceNameString;
502       }
503       else
504       {
505          dataSourceName = defaultValues.getDataSourceName();
506       }
507
508       // get the datasource mapping for this datasource (optional, but always
509
// set in standardjbosscmp-jdbc.xml)
510
String JavaDoc datasourceMappingString = MetaData.getOptionalChildContent(element, "datasource-mapping");
511       if(datasourceMappingString != null)
512       {
513          datasourceMappingName = datasourceMappingString;
514          datasourceMapping = jdbcApplication.getTypeMappingByName(datasourceMappingString);
515          if(datasourceMapping == null)
516          {
517             throw new DeploymentException(
518                "Error in jbosscmp-jdbc.xml : "
519                +
520                "datasource-mapping "
521                + datasourceMappingString +
522                " not found"
523             );
524          }
525       }
526       else if(defaultValues.datasourceMappingName != null && defaultValues.datasourceMapping != null)
527       {
528          datasourceMappingName = null;
529          datasourceMapping = defaultValues.datasourceMapping;
530       }
531       else
532       {
533          datasourceMappingName = null;
534          datasourceMapping = obtainTypeMappingFromLibrary(dataSourceName);
535       }
536
537       // get table name
538
String JavaDoc tableStr = MetaData.getOptionalChildContent(element, "table-name");
539       if(tableStr != null)
540       {
541          tableName = tableStr;
542       }
543       else
544       {
545          tableName = defaultValues.getDefaultTableName();
546       }
547
548       // create table? If not provided, keep default.
549
String JavaDoc createStr = MetaData.getOptionalChildContent(element, "create-table");
550       if(createStr != null)
551       {
552          createTable = Boolean.valueOf(createStr).booleanValue();
553       }
554       else
555       {
556          createTable = defaultValues.getCreateTable();
557       }
558
559       // remove table? If not provided, keep default.
560
String JavaDoc removeStr = MetaData.getOptionalChildContent(element, "remove-table");
561       if(removeStr != null)
562       {
563          removeTable = Boolean.valueOf(removeStr).booleanValue();
564       }
565       else
566       {
567          removeTable = defaultValues.getRemoveTable();
568       }
569
570       // alter table? If not provided, keep default.
571
String JavaDoc alterStr = MetaData.getOptionalChildContent(element, "alter-table");
572       if(alterStr != null)
573       {
574          alterTable = Boolean.valueOf(alterStr).booleanValue();
575       }
576       else
577       {
578          alterTable = defaultValues.getAlterTable();
579       }
580
581
582       // get the SQL command to execute after table creation
583
Element JavaDoc posttc = MetaData.getOptionalChild(element, "post-table-create");
584       if(posttc != null)
585       {
586          Iterator JavaDoc it = MetaData.getChildrenByTagName(posttc, "sql-statement");
587          tablePostCreateCmd = new ArrayList JavaDoc();
588          while(it.hasNext())
589          {
590             Element JavaDoc etmp = (Element JavaDoc) it.next();
591             tablePostCreateCmd.add(MetaData.getElementContent(etmp));
592          }
593       }
594       else
595       {
596          tablePostCreateCmd = defaultValues.getDefaultTablePostCreateCmd();
597       }
598
599       // read-only
600
String JavaDoc readOnlyStr = MetaData.getOptionalChildContent(element, "read-only");
601       if(readOnlyStr != null)
602       {
603          readOnly = Boolean.valueOf(readOnlyStr).booleanValue();
604       }
605       else
606       {
607          readOnly = defaultValues.isReadOnly();
608       }
609
610       // read-time-out
611
String JavaDoc readTimeOutStr = MetaData.getOptionalChildContent(element, "read-time-out");
612       if(readTimeOutStr != null)
613       {
614          try
615          {
616             readTimeOut = Integer.parseInt(readTimeOutStr);
617          }
618          catch(NumberFormatException JavaDoc e)
619          {
620             throw new DeploymentException(
621                "Invalid number format in " +
622                "read-time-out '" + readTimeOutStr + "': " + e
623             );
624          }
625       }
626       else
627       {
628          readTimeOut = defaultValues.getReadTimeOut();
629       }
630
631       String JavaDoc sForUpStr = MetaData.getOptionalChildContent(element, "row-locking");
632       if(sForUpStr != null)
633       {
634          rowLocking = !isReadOnly() && (Boolean.valueOf(sForUpStr).booleanValue());
635       }
636       else
637       {
638          rowLocking = defaultValues.hasRowLocking();
639       }
640
641       // primary key constraint? If not provided, keep default.
642
String JavaDoc pkStr = MetaData.getOptionalChildContent(element, "pk-constraint");
643       if(pkStr != null)
644       {
645          primaryKeyConstraint = Boolean.valueOf(pkStr).booleanValue();
646       }
647       else
648       {
649          primaryKeyConstraint = defaultValues.hasPrimaryKeyConstraint();
650       }
651
652       // list-cache-max
653
String JavaDoc listCacheMaxStr = MetaData.getOptionalChildContent(element, "list-cache-max");
654       if(listCacheMaxStr != null)
655       {
656          try
657          {
658             listCacheMax = Integer.parseInt(listCacheMaxStr);
659          }
660          catch(NumberFormatException JavaDoc e)
661          {
662             throw new DeploymentException(
663                "Invalid number format in read-" +
664                "ahead list-cache-max '" + listCacheMaxStr + "': " + e
665             );
666          }
667          if(listCacheMax < 0)
668          {
669             throw new DeploymentException(
670                "Negative value for read ahead " +
671                "list-cache-max '" + listCacheMaxStr + "'."
672             );
673          }
674       }
675       else
676       {
677          listCacheMax = defaultValues.getListCacheMax();
678       }
679
680       // fetch-size
681
String JavaDoc fetchSizeStr = MetaData.getOptionalChildContent(element, "fetch-size");
682       if(fetchSizeStr != null)
683       {
684          try
685          {
686             fetchSize = Integer.parseInt(fetchSizeStr);
687          }
688          catch(NumberFormatException JavaDoc e)
689          {
690             throw new DeploymentException(
691                "Invalid number format in " +
692                "fetch-size '" + fetchSizeStr + "': " + e
693             );
694          }
695          if(fetchSize < 0)
696          {
697             throw new DeploymentException(
698                "Negative value for fetch size " +
699                "fetch-size '" + fetchSizeStr + "'."
700             );
701          }
702       }
703       else
704       {
705          fetchSize = defaultValues.getFetchSize();
706       }
707
708       String JavaDoc compiler = MetaData.getOptionalChildContent(element, "ql-compiler");
709       if(compiler == null)
710       {
711          qlCompiler = defaultValues.qlCompiler;
712       }
713       else
714       {
715          try
716          {
717             qlCompiler = GetTCLAction.getContextClassLoader().loadClass(compiler);
718          }
719          catch(ClassNotFoundException JavaDoc e)
720          {
721             throw new DeploymentException("Failed to load compiler implementation: " + compiler);
722          }
723       }
724
725       // throw runtime exceptions ? If not provided, keep default.
726
String JavaDoc throwRuntimeExceptionsStr = MetaData.getOptionalChildContent(element, "throw-runtime-exceptions");
727       if(throwRuntimeExceptionsStr != null)
728       {
729           throwRuntimeExceptions = Boolean.valueOf(throwRuntimeExceptionsStr).booleanValue();
730       }
731       else
732       {
733           throwRuntimeExceptions = defaultValues.getThrowRuntimeExceptions();
734       }
735
736
737       //
738
// cmp fields
739
//
740

741       // update all existing queries with the new read ahead value
742
for(Iterator JavaDoc cmpFieldIterator = defaultValues.cmpFields.iterator();
743          cmpFieldIterator.hasNext();)
744       {
745
746          JDBCCMPFieldMetaData cmpField = new JDBCCMPFieldMetaData(this, (JDBCCMPFieldMetaData) cmpFieldIterator.next());
747          cmpFields.add(cmpField);
748          cmpFieldsByName.put(cmpField.getFieldName(), cmpField);
749       }
750
751       // apply new configurations to the cmpfields
752
for(Iterator JavaDoc i = MetaData.getChildrenByTagName(element, "cmp-field"); i.hasNext();)
753       {
754          Element JavaDoc cmpFieldElement = (Element JavaDoc) i.next();
755          String JavaDoc fieldName = MetaData.getUniqueChildContent(cmpFieldElement, "field-name");
756
757          JDBCCMPFieldMetaData oldCMPField = (JDBCCMPFieldMetaData) cmpFieldsByName.get(fieldName);
758          if(oldCMPField == null)
759          {
760             throw new DeploymentException("CMP field not found : fieldName=" + fieldName);
761          }
762          JDBCCMPFieldMetaData cmpFieldMetaData = new JDBCCMPFieldMetaData(
763             this,
764             cmpFieldElement,
765             oldCMPField
766          );
767
768          // replace the old cmp meta data with the new
769
cmpFieldsByName.put(fieldName, cmpFieldMetaData);
770          int index = cmpFields.indexOf(oldCMPField);
771          cmpFields.remove(oldCMPField);
772          cmpFields.add(index, cmpFieldMetaData);
773       }
774
775       // unknown primary key field
776
if(primaryKeyClass == java.lang.Object JavaDoc.class)
777       {
778          Element JavaDoc upkElement = MetaData.getOptionalChild(element, "unknown-pk");
779          if(upkElement != null)
780          {
781             // assume now there is only one upk field
782
JDBCCMPFieldMetaData oldUpkField = null;
783             for(Iterator JavaDoc iter = cmpFields.iterator(); iter.hasNext();)
784             {
785                JDBCCMPFieldMetaData cmpField = (JDBCCMPFieldMetaData) iter.next();
786                if(cmpField.isUnknownPkField())
787                {
788                   oldUpkField = cmpField;
789                   break;
790                }
791             }
792
793             // IMO, this is a redundant check
794
if(oldUpkField == null)
795             {
796                oldUpkField = new JDBCCMPFieldMetaData(this);
797             }
798
799             JDBCCMPFieldMetaData upkField = new JDBCCMPFieldMetaData(this, upkElement, oldUpkField);
800
801             // remove old upk field
802
cmpFieldsByName.remove(oldUpkField.getFieldName());
803             cmpFieldsByName.put(upkField.getFieldName(), upkField);
804
805             int oldUpkFieldInd = cmpFields.indexOf(oldUpkField);
806             cmpFields.remove(oldUpkField);
807             cmpFields.add(oldUpkFieldInd, upkField);
808          }
809       }
810
811       // load-loads
812
loadGroups.putAll(defaultValues.loadGroups);
813       loadLoadGroupsXml(element);
814
815       // eager-load
816
Element JavaDoc eagerLoadGroupElement = MetaData.getOptionalChild(element, "eager-load-group");
817       if(eagerLoadGroupElement != null)
818       {
819          String JavaDoc eagerLoadGroupTmp = MetaData.getElementContent(eagerLoadGroupElement);
820          if(eagerLoadGroupTmp != null && eagerLoadGroupTmp.trim().length() == 0)
821          {
822             eagerLoadGroupTmp = null;
823          }
824          if(eagerLoadGroupTmp != null
825             && !eagerLoadGroupTmp.equals("*")
826             && !loadGroups.containsKey(eagerLoadGroupTmp))
827          {
828             throw new DeploymentException(
829                "Eager load group not found: " +
830                "eager-load-group=" + eagerLoadGroupTmp
831             );
832          }
833          eagerLoadGroup = eagerLoadGroupTmp;
834       }
835       else
836       {
837          eagerLoadGroup = defaultValues.getEagerLoadGroup();
838       }
839
840       // lazy-loads
841
lazyLoadGroups.addAll(defaultValues.lazyLoadGroups);
842       loadLazyLoadGroupsXml(element);
843
844       // read-ahead
845
Element JavaDoc readAheadElement = MetaData.getOptionalChild(element, "read-ahead");
846       if(readAheadElement != null)
847       {
848          readAhead = new JDBCReadAheadMetaData(readAheadElement, defaultValues.getReadAhead());
849       }
850       else
851       {
852          readAhead = defaultValues.readAhead;
853       }
854
855       String JavaDoc value = MetaData.getOptionalChildContent(element, "clean-read-ahead-on-load");
856       if("true".equalsIgnoreCase(value))
857       {
858          cleanReadAheadOnLoad = true;
859       }
860       else if("false".equalsIgnoreCase(value))
861       {
862          cleanReadAheadOnLoad = false;
863       }
864       else if(value == null)
865       {
866          cleanReadAheadOnLoad = defaultValues.cleanReadAheadOnLoad;
867       }
868       else
869       {
870          throw new DeploymentException("Failed to deploy " + entityName +
871             ": allowed values for clean-read-ahead-on-load are true and false but got " + value);
872       }
873
874       // optimistic locking group
875
Element JavaDoc optimisticLockingEl = MetaData.getOptionalChild(element, "optimistic-locking");
876       if(optimisticLockingEl != null)
877       {
878          optimisticLocking = new JDBCOptimisticLockingMetaData(this, optimisticLockingEl);
879       }
880       else
881       {
882          optimisticLocking = defaultValues.getOptimisticLocking();
883       }
884
885       // audit
886
Element JavaDoc auditElement = MetaData.getOptionalChild(element, "audit");
887       if(auditElement != null)
888       {
889          audit = new JDBCAuditMetaData(this, auditElement);
890       }
891       else
892       {
893          audit = defaultValues.getAudit();
894       }
895
896       // queries
897

898       // update all existing queries with the new read ahead value
899
for(Iterator JavaDoc queriesIterator = defaultValues.queries.values().iterator();
900          queriesIterator.hasNext();)
901       {
902          JDBCQueryMetaData query = JDBCQueryMetaDataFactory.createJDBCQueryMetaData(
903             (JDBCQueryMetaData) queriesIterator.next(),
904             readAhead, qlCompiler
905          );
906          queries.put(query.getMethod(), query);
907       }
908
909       // apply new configurations to the queries
910
for(Iterator JavaDoc queriesIterator = MetaData.getChildrenByTagName(element, "query");
911          queriesIterator.hasNext();)
912       {
913          Element JavaDoc queryElement = (Element JavaDoc) queriesIterator.next();
914          Map JavaDoc newQueries = queryFactory.createJDBCQueryMetaData(
915             queryElement,
916             defaultValues.queries,
917             readAhead
918          );
919
920          // overrides defaults added above
921
queries.putAll(newQueries);
922       }
923
924       // get the entity command for this entity
925
Element JavaDoc entityCommandEl = MetaData.getOptionalChild(element, "entity-command");
926       if(entityCommandEl != null)
927       {
928          // command name in xml
929
String JavaDoc entityCommandName = entityCommandEl.getAttribute("name");
930
931          // default entity command
932
// The logic to assign the default value:
933
// - if entity-command isn't specified in the entity element,
934
// then it is assigned from the defaults;
935
// - if command name in entity equals command name in defaults
936
// then it is assigned from the defaults
937
// - else try to find a command in entity-commands with the command
938
// name specified in the entity.
939
// if the match is found it'll be the default, else default is null
940
JDBCEntityCommandMetaData defaultEntityCommand = defaultValues.getEntityCommand();
941
942          if((defaultEntityCommand == null)
943             || (!entityCommandName.equals(defaultEntityCommand.getCommandName())))
944          {
945             defaultEntityCommand = jdbcApplication.getEntityCommandByName(entityCommandName);
946          }
947
948          if(defaultEntityCommand != null)
949          {
950             entityCommand = new JDBCEntityCommandMetaData(entityCommandEl, defaultEntityCommand);
951          }
952          else
953          {
954             entityCommand = new JDBCEntityCommandMetaData(entityCommandEl);
955          }
956       }
957       else
958       {
959          entityCommand = defaultValues.getEntityCommand();
960       }
961    }
962
963    /**
964     * Loads the load groups of cmp fields from the xml element
965     */

966    private void loadLoadGroupsXml(Element JavaDoc element)
967       throws DeploymentException
968    {
969
970       Element JavaDoc loadGroupsElement = MetaData.getOptionalChild(element, "load-groups");
971       if(loadGroupsElement == null)
972       {
973          // no info, default work already done in constructor
974
return;
975       }
976
977       // only allowed for cmp 2.x
978
if(isCMP1x)
979       {
980          throw new DeploymentException(
981             "load-groups are only allowed " +
982             "for CMP 2.x"
983          );
984       }
985
986       // load each group
987
Iterator JavaDoc groups = MetaData.getChildrenByTagName(loadGroupsElement, "load-group");
988       while(groups.hasNext())
989       {
990          Element JavaDoc groupElement = (Element JavaDoc) groups.next();
991
992          // get the load-group-name
993
String JavaDoc loadGroupName = MetaData.getUniqueChildContent(groupElement, "load-group-name");
994          if(loadGroups.containsKey(loadGroupName))
995          {
996             throw new DeploymentException(
997                "Load group already defined: " +
998                " load-group-name=" + loadGroupName
999             );
1000         }
1001         if(loadGroupName.equals("*"))
1002         {
1003            throw new DeploymentException(
1004               "The * load group is automatically " +
1005               "defined and can't be overriden"
1006            );
1007         }
1008         ArrayList JavaDoc group = new ArrayList JavaDoc();
1009
1010         // add each field
1011
Iterator JavaDoc fields = MetaData.getChildrenByTagName(groupElement, "field-name");
1012         while(fields.hasNext())
1013         {
1014            String JavaDoc fieldName = MetaData.getElementContent((Element JavaDoc) fields.next());
1015
1016            // check if the field is a cmp field that it is not a pk memeber
1017
JDBCCMPFieldMetaData field = getCMPFieldByName(fieldName);
1018            if(field != null && field.isPrimaryKeyMember())
1019            {
1020               throw new DeploymentException(
1021                  "Primary key fields can not be"
1022                  +
1023                  " a member of a load group: "
1024                  +
1025                  " load-group-name="
1026                  + loadGroupName +
1027                  " field-name=" + fieldName
1028               );
1029            }
1030
1031            group.add(fieldName);
1032         }
1033
1034         loadGroups.put(loadGroupName, Collections.unmodifiableList(group));
1035      }
1036   }
1037
1038   /**
1039    * Loads the list of lazy load groups from the xml element.
1040    */

1041   private void loadLazyLoadGroupsXml(Element JavaDoc element)
1042      throws DeploymentException
1043   {
1044      Element JavaDoc lazyLoadGroupsElement = MetaData.getOptionalChild(element, "lazy-load-groups");
1045
1046      // If no info, we're done. Default work was already done in constructor.
1047
if(lazyLoadGroupsElement == null)
1048      {
1049         return;
1050      }
1051
1052      // only allowed for cmp 2.x
1053
if(isCMP1x)
1054      {
1055         throw new DeploymentException("lazy-load-groups is only allowed for CMP 2.x");
1056      }
1057
1058      // get the fields
1059
Iterator JavaDoc loadGroupNames = MetaData.getChildrenByTagName(lazyLoadGroupsElement, "load-group-name");
1060      while(loadGroupNames.hasNext())
1061      {
1062         String JavaDoc loadGroupName = MetaData.getElementContent((Element JavaDoc) loadGroupNames.next());
1063         if(!loadGroupName.equals("*") && !loadGroups.containsKey(loadGroupName))
1064         {
1065            throw new DeploymentException(
1066               "Lazy load group not found: " +
1067               "load-group-name=" + loadGroupName
1068            );
1069         }
1070
1071         lazyLoadGroups.add(loadGroupName);
1072      }
1073
1074   }
1075
1076   /**
1077    * Gets the meta data for the application of which this entity is a member.
1078    *
1079    * @return the meta data for the application that this entity is a memeber
1080    */

1081   public JDBCApplicationMetaData getJDBCApplication()
1082   {
1083      return jdbcApplication;
1084   }
1085
1086   /**
1087    * Gets the name of the datasource in jndi for this entity
1088    *
1089    * @return the name of datasource in jndi
1090    */

1091   public String JavaDoc getDataSourceName()
1092   {
1093      return dataSourceName;
1094   }
1095
1096   /**
1097    * Gets the jdbc type mapping for this entity
1098    *
1099    * @return the jdbc type mapping for this entity
1100    */

1101   public JDBCTypeMappingMetaData getTypeMapping() throws DeploymentException
1102   {
1103      if(datasourceMapping == null)
1104      {
1105         throw new DeploymentException("type-mapping is not initialized: " + dataSourceName
1106            + " was not deployed or type-mapping was not configured.");
1107      }
1108
1109      return datasourceMapping;
1110   }
1111
1112   /**
1113    * Gets the name of this entity. The name come from the ejb-jar.xml file.
1114    *
1115    * @return the name of this entity
1116    */

1117   public String JavaDoc getName()
1118   {
1119      return entityName;
1120   }
1121
1122   /**
1123    * Gets the abstract shcema name of this entity. The name come from
1124    * the ejb-jar.xml file.
1125    *
1126    * @return the abstract schema name of this entity
1127    */

1128   public String JavaDoc getAbstractSchemaName()
1129   {
1130      return abstractSchemaName;
1131   }
1132
1133   /**
1134    * Gets the class loaded which is used to load all classes used by this
1135    * entity
1136    *
1137    * @return the class loader which is used to load all classes used by
1138    * this entity
1139    */

1140   public ClassLoader JavaDoc getClassLoader()
1141   {
1142      return jdbcApplication.getClassLoader();
1143   }
1144
1145   /**
1146    * Gets the implementation class of this entity
1147    *
1148    * @return the implementation class of this entity
1149    */

1150   public Class JavaDoc getEntityClass()
1151   {
1152      return entityClass;
1153   }
1154
1155   /**
1156    * Gets the home class of this entity
1157    *
1158    * @return the home class of this entity
1159    */

1160   public Class JavaDoc getHomeClass()
1161   {
1162      return homeClass;
1163   }
1164
1165   /**
1166    * Gets the remote class of this entity
1167    *
1168    * @return the remote class of this entity
1169    */

1170   public Class JavaDoc getRemoteClass()
1171   {
1172      return remoteClass;
1173   }
1174
1175   /**
1176    * Gets the local home class of this entity
1177    *
1178    * @return the local home class of this entity
1179    */

1180   public Class JavaDoc getLocalHomeClass()
1181   {
1182      return localHomeClass;
1183   }
1184
1185   /**
1186    * Gets the local class of this entity
1187    *
1188    * @return the local class of this entity
1189    */

1190   public Class JavaDoc getLocalClass()
1191   {
1192      return localClass;
1193   }
1194
1195   /**
1196    * Does this entity use CMP version 1.x
1197    *
1198    * @return true if this entity used CMP version 1.x; otherwise false
1199    */

1200   public boolean isCMP1x()
1201   {
1202      return isCMP1x;
1203   }
1204
1205   /**
1206    * Gets the cmp fields of this entity
1207    *
1208    * @return an unmodifiable collection of JDBCCMPFieldMetaData objects
1209    */

1210   public List JavaDoc getCMPFields()
1211   {
1212      return Collections.unmodifiableList(cmpFields);
1213   }
1214
1215   /**
1216    * Gets the name of the eager load group. This name can be used to
1217    * look up the load group.
1218    *
1219    * @return the name of the eager load group
1220    */

1221   public String JavaDoc getEagerLoadGroup()
1222   {
1223      return eagerLoadGroup;
1224   }
1225
1226   /**
1227    * Gets the collection of lazy load group names.
1228    *
1229    * @return an unmodifiable collection of load group names
1230    */

1231   public List JavaDoc getLazyLoadGroups()
1232   {
1233      return Collections.unmodifiableList(lazyLoadGroups);
1234   }
1235
1236   /**
1237    * Gets the map from load grou name to a List of field names, which
1238    * forms a logical load group.
1239    *
1240    * @return an unmodifiable map of load groups (Lists) by group name.
1241    */

1242   public Map JavaDoc getLoadGroups()
1243   {
1244      return Collections.unmodifiableMap(loadGroups);
1245   }
1246
1247   /**
1248    * Gets the load group with the specified name.
1249    *
1250    * @return the load group with the specified name
1251    * @throws DeploymentException if group with the specified name is not found
1252    */

1253   public List JavaDoc getLoadGroup(String JavaDoc name) throws DeploymentException
1254   {
1255      List JavaDoc group = (List JavaDoc) loadGroups.get(name);
1256      if(group == null)
1257      {
1258         throw new DeploymentException("Unknown load group: name=" + name);
1259      }
1260      return group;
1261   }
1262
1263   /**
1264    * Returns optimistic locking metadata
1265    */

1266   public JDBCOptimisticLockingMetaData getOptimisticLocking()
1267   {
1268      return optimisticLocking;
1269   }
1270
1271   /**
1272    * Returns audit metadata
1273    */

1274   public JDBCAuditMetaData getAudit()
1275   {
1276      return audit;
1277   }
1278
1279   /**
1280    * Gets the cmp field with the specified name
1281    *
1282    * @param name the name of the desired field
1283    * @return the cmp field with the specified name or null if not found
1284    */

1285   public JDBCCMPFieldMetaData getCMPFieldByName(String JavaDoc name)
1286   {
1287      return (JDBCCMPFieldMetaData) cmpFieldsByName.get(name);
1288   }
1289
1290   /**
1291    * Gets the name of the table to which this entity is persisted
1292    *
1293    * @return the name of the table to which this entity is persisted
1294    */

1295   public String JavaDoc getDefaultTableName()
1296   {
1297      return tableName;
1298   }
1299
1300   /**
1301    * Gets the flag used to determine if the store manager should attempt to
1302    * create database table when the entity is deployed.
1303    *
1304    * @return true if the store manager should attempt to create the table
1305    */

1306   public boolean getCreateTable()
1307   {
1308      return createTable;
1309   }
1310
1311   /**
1312    * Gets the flag used to determine if the store manager should attempt to
1313    * remove database table when the entity is undeployed.
1314    *
1315    * @return true if the store manager should attempt to remove the table
1316    */

1317   public boolean getRemoveTable()
1318   {
1319      return removeTable;
1320   }
1321
1322   /**
1323    * Gets the flag used to determine if the store manager should attempt to
1324    * alter table when the entity is deployed.
1325    */

1326   public boolean getAlterTable()
1327   {
1328      return alterTable;
1329   }
1330
1331   /**
1332    * Get the (user-defined) SQL commands that sould be issued after table
1333    * creation
1334    *
1335    * @return the SQL command to issue to the DB-server
1336    */

1337   public ArrayList JavaDoc getDefaultTablePostCreateCmd()
1338   {
1339      return tablePostCreateCmd;
1340   }
1341
1342   /**
1343    * Gets the flag used to determine if the store manager should add a
1344    * priary key constraint when creating the table
1345    *
1346    * @return true if the store manager should add a primary key constraint to
1347    * the create table sql statement
1348    */

1349   public boolean hasPrimaryKeyConstraint()
1350   {
1351      return primaryKeyConstraint;
1352   }
1353
1354   /**
1355    * Gets the flag used to determine if the store manager should do row locking
1356    * when loading entity beans
1357    *
1358    * @return true if the store manager should add a row locking
1359    * clause when selecting data from the table
1360    */

1361   public boolean hasRowLocking()
1362   {
1363      return rowLocking;
1364   }
1365
1366   /**
1367    * The maximum number of qurey result lists that will be tracked.
1368    */

1369   public int getListCacheMax()
1370   {
1371      return listCacheMax;
1372   }
1373
1374   /**
1375    * The number of rows that the database driver should get in a single
1376    * trip to the database.
1377    */

1378   public int getFetchSize()
1379   {
1380      return fetchSize;
1381   }
1382
1383
1384   /**
1385    * Gets the queries defined on this entity
1386    *
1387    * @return an unmodifiable collection of JDBCQueryMetaData objects
1388    */

1389   public Collection JavaDoc getQueries()
1390   {
1391      return Collections.unmodifiableCollection(queries.values());
1392   }
1393
1394   /**
1395    * @param method finder method name.
1396    * @return corresponding query metadata or null.
1397    */

1398   public JDBCQueryMetaData getQueryMetaDataForMethod(Method JavaDoc method)
1399   {
1400      return (JDBCQueryMetaData) queries.get(method);
1401   }
1402
1403   /**
1404    * Get the relationsip roles of this entity.
1405    * Items are instance of JDBCRelationshipRoleMetaData.
1406    *
1407    * @return an unmodifiable collection of the relationship roles defined
1408    * for this entity
1409    */

1410   public Collection JavaDoc getRelationshipRoles()
1411   {
1412      return jdbcApplication.getRolesForEntity(entityName);
1413   }
1414
1415   /**
1416    * Gets the primary key class for this entity
1417    *
1418    * @return the primary key class for this entity
1419    */

1420   public Class JavaDoc getPrimaryKeyClass()
1421   {
1422      return primaryKeyClass;
1423   }
1424
1425   /**
1426    * Gets the entity command metadata
1427    *
1428    * @return the entity command metadata
1429    */

1430   public JDBCEntityCommandMetaData getEntityCommand()
1431   {
1432      return entityCommand;
1433   }
1434
1435   /**
1436    * Is this entity read only? A readonly entity will never be stored into
1437    * the database.
1438    *
1439    * @return true if this entity is read only
1440    */

1441   public boolean isReadOnly()
1442   {
1443      return readOnly;
1444   }
1445
1446   /**
1447    * How long is a read of this entity valid. This property should only be
1448    * used on read only entities, and determines how long the data read from
1449    * the database is valid. When the read times out it should be reread from
1450    * the database. If the value is -1 and the entity is not using commit
1451    * option a, the read is only valid for the length of the transaction in
1452    * which it was loaded.
1453    *
1454    * @return the length of time that a read is valid or -1 if the read is only
1455    * valid for the length of the transaction
1456    */

1457   public int getReadTimeOut()
1458   {
1459      return readTimeOut;
1460   }
1461
1462   /**
1463    * Gets the name of the primary key field of this entity or null if
1464    * the primary key is multivalued
1465    *
1466    * @return the name of the primary key field of this entity or null
1467    * if the primary key is multivalued
1468    */

1469   public String JavaDoc getPrimaryKeyFieldName()
1470   {
1471      return primaryKeyFieldName;
1472   }
1473
1474
1475   /**
1476    * Gets the read ahead meta data for this entity.
1477    *
1478    * @return the read ahead meta data for this entity.
1479    */

1480   public JDBCReadAheadMetaData getReadAhead()
1481   {
1482      return readAhead;
1483   }
1484
1485   public Class JavaDoc getQLCompiler()
1486   {
1487      return qlCompiler;
1488   }
1489
1490   /**
1491    * Is the throw-runtime-exceptions meta data for this entity is true.
1492    *
1493    * @return the throw-runtime-exceptions meta data for this entity.
1494    */

1495   public boolean isThrowRuntimeExceptions()
1496   {
1497      return throwRuntimeExceptions;
1498   }
1499   /**
1500    * Gets the throw-runtime-exceptions meta data for this entity.
1501    *
1502    * @return the throw-runtime-exceptions meta data for this entity.
1503    */

1504   public boolean getThrowRuntimeExceptions()
1505   {
1506      return throwRuntimeExceptions;
1507   }
1508   
1509
1510   public boolean isCleanReadAheadOnLoad()
1511   {
1512      return cleanReadAheadOnLoad;
1513   }
1514
1515   public static JDBCTypeMappingMetaData obtainTypeMappingFromLibrary(String JavaDoc dataSourceName)
1516      throws DeploymentException
1517   {
1518      JDBCTypeMappingMetaData typeMapping = null;
1519
1520      String JavaDoc datasource;
1521      if(dataSourceName.startsWith("java:"))
1522      {
1523         datasource = dataSourceName.substring("java:".length());
1524         if(datasource.startsWith("/"))
1525         {
1526            datasource = datasource.substring(1);
1527         }
1528      }
1529      else
1530      {
1531         datasource = dataSourceName;
1532      }
1533
1534      final ObjectName JavaDoc metadataService;
1535      final String JavaDoc str = "jboss.jdbc:service=metadata,datasource=" + datasource;
1536      try
1537      {
1538         metadataService = new ObjectName JavaDoc(str);
1539      }
1540      catch(MalformedObjectNameException JavaDoc e)
1541      {
1542         throw new DeploymentException("Failed to create ObjectName for datasource metadata MBean: " + str, e);
1543      }
1544
1545      try
1546      {
1547         final MBeanServer JavaDoc server = MBeanServerLocator.locateJBoss();
1548         if(server.isRegistered(metadataService))
1549         {
1550            typeMapping = (JDBCTypeMappingMetaData)server.getAttribute(metadataService, "TypeMappingMetaData");
1551         }
1552      }
1553      catch(Exception JavaDoc e)
1554      {
1555         throw new DeploymentException("Failed to obtain type-mapping metadata from the metadata library MBean: " +
1556            e.getMessage(), e);
1557      }
1558
1559      /*
1560      if(typeMapping == null)
1561      {
1562         throw new DeploymentException(
1563            "type-mapping for datasource " + datasource + " not found in the library. " +
1564            "Check the value of metadata/type-mapping in the -ds.xml file."
1565         );
1566      }
1567      */

1568
1569      return typeMapping;
1570   }
1571
1572   /**
1573    * Compares this JDBCEntityMetaData against the specified object. Returns
1574    * true if the objects are the same. Two JDBCEntityMetaData are the same
1575    * if they both have the same name and are defined in the same application.
1576    *
1577    * @param o the reference object with which to compare
1578    * @return true if this object is the same as the object argument;
1579    * false otherwise
1580    */

1581   public boolean equals(Object JavaDoc o)
1582   {
1583      if(o instanceof JDBCEntityMetaData)
1584      {
1585         JDBCEntityMetaData entity = (JDBCEntityMetaData) o;
1586         return entityName.equals(entity.entityName) &&
1587            jdbcApplication.equals(entity.jdbcApplication);
1588      }
1589      return false;
1590   }
1591
1592   /**
1593    * Returns a hashcode for this JDBCEntityMetaData. The hashcode is computed
1594    * based on the hashCode of the declaring application and the hashCode of
1595    * the entityName
1596    *
1597    * @return a hash code value for this object
1598    */

1599   public int hashCode()
1600   {
1601      int result = 17;
1602      result = 37 * result + jdbcApplication.hashCode();
1603      result = 37 * result + entityName.hashCode();
1604      return result;
1605   }
1606
1607   /**
1608    * Returns a string describing this JDBCEntityMetaData. The exact details
1609    * of the representation are unspecified and subject to change, but the
1610    * following may be regarded as typical:
1611    * <p/>
1612    * "[JDBCEntityMetaData: entityName=UserEJB]"
1613    *
1614    * @return a string representation of the object
1615    */

1616   public String JavaDoc toString()
1617   {
1618      return "[JDBCEntityMetaData : entityName=" + entityName + "]";
1619   }
1620}
1621
Popular Tags