KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ws > jaxme > pm > generator > jdbc > JaxMeJdbcSG


1 /*
2  * Copyright 2003, 2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15
16  */

17 package org.apache.ws.jaxme.pm.generator.jdbc;
18
19 import java.sql.Connection JavaDoc;
20 import java.sql.DriverManager JavaDoc;
21 import java.sql.SQLException JavaDoc;
22 import java.sql.Types JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.List JavaDoc;
27
28 import javax.naming.NamingException JavaDoc;
29
30 import org.apache.ws.jaxme.generator.Generator;
31 import org.apache.ws.jaxme.generator.SchemaReader;
32 import org.apache.ws.jaxme.generator.sg.AttributeSG;
33 import org.apache.ws.jaxme.generator.sg.AttributeSGChain;
34 import org.apache.ws.jaxme.generator.sg.ComplexContentSG;
35 import org.apache.ws.jaxme.generator.sg.ComplexTypeSG;
36 import org.apache.ws.jaxme.generator.sg.Context;
37 import org.apache.ws.jaxme.generator.sg.GroupSG;
38 import org.apache.ws.jaxme.generator.sg.ObjectSG;
39 import org.apache.ws.jaxme.generator.sg.ParticleSG;
40 import org.apache.ws.jaxme.generator.sg.SGFactory;
41 import org.apache.ws.jaxme.generator.sg.SGFactoryChain;
42 import org.apache.ws.jaxme.generator.sg.SchemaSGChain;
43 import org.apache.ws.jaxme.generator.sg.TypeSGChain;
44 import org.apache.ws.jaxme.generator.sg.impl.AttributeSGImpl;
45 import org.apache.ws.jaxme.generator.sg.impl.JaxMeSchemaReader;
46 import org.apache.ws.jaxme.generator.sg.impl.SGFactoryChainImpl;
47 import org.apache.ws.jaxme.logging.Logger;
48 import org.apache.ws.jaxme.logging.LoggerAccess;
49 import org.apache.ws.jaxme.sqls.Column;
50 import org.apache.ws.jaxme.sqls.SQLFactory;
51 import org.apache.ws.jaxme.sqls.Table;
52 import org.apache.ws.jaxme.sqls.impl.SQLFactoryImpl;
53 import org.apache.ws.jaxme.util.ClassLoader;
54 import org.apache.ws.jaxme.xs.XSAnnotation;
55 import org.apache.ws.jaxme.xs.XSAttribute;
56 import org.apache.ws.jaxme.xs.XSObject;
57 import org.apache.ws.jaxme.xs.XSSchema;
58 import org.apache.ws.jaxme.xs.XSType;
59 import org.apache.ws.jaxme.xs.parser.XsObjectCreator;
60 import org.apache.ws.jaxme.xs.parser.impl.LocSAXException;
61 import org.apache.ws.jaxme.xs.types.XSBase64Binary;
62 import org.apache.ws.jaxme.xs.types.XSBoolean;
63 import org.apache.ws.jaxme.xs.types.XSByte;
64 import org.apache.ws.jaxme.xs.types.XSDate;
65 import org.apache.ws.jaxme.xs.types.XSDateTime;
66 import org.apache.ws.jaxme.xs.types.XSDouble;
67 import org.apache.ws.jaxme.xs.types.XSFloat;
68 import org.apache.ws.jaxme.xs.types.XSInt;
69 import org.apache.ws.jaxme.xs.types.XSShort;
70 import org.apache.ws.jaxme.xs.types.XSString;
71 import org.apache.ws.jaxme.xs.types.XSTime;
72 import org.apache.ws.jaxme.xs.xml.XsEAppinfo;
73 import org.apache.ws.jaxme.xs.xml.XsObject;
74 import org.apache.ws.jaxme.xs.xml.XsQName;
75 import org.xml.sax.Attributes JavaDoc;
76 import org.xml.sax.Locator JavaDoc;
77 import org.xml.sax.SAXException JavaDoc;
78
79
80 /** <p>A schema writer for creation of an object relational
81  * mapping.</p>
82  *
83  * @author <a HREF="mailto:joe@ispsoft.de">Jochen Wiedmann</a>
84  */

85 public class JaxMeJdbcSG extends SGFactoryChainImpl {
86   Logger log = LoggerAccess.getLogger(JaxMeJdbcSG.class);
87
88   /** A database mode specifies, how JDBC metadata is
89    * being interpreted. The main use is for Oracle, which
90    * has a rather peculiar understanding of JDBC metadata.
91    */

92   public static class Mode {
93     private String JavaDoc name;
94     private Mode(String JavaDoc pName) { name = pName; }
95     public String JavaDoc toString() { return name; }
96     /** Returns the modes name.
97      */

98     public String JavaDoc getName() { return name; }
99     public int hashCode() { return name.hashCode(); }
100     public boolean equals(Object JavaDoc o) {
101       if (o == null || !(o instanceof Mode)) {
102         return false;
103       } else {
104         return name.equals(((Mode) o).name);
105       }
106     }
107     /** Returns an instance of <code>Mode</code> with
108      * the given name.
109      * @throws IllegalArgumentException The mode name is invalid.
110      */

111     public static Mode valueOf(String JavaDoc pMode) {
112       if ("GENERIC".equalsIgnoreCase(pMode)) {
113         return GENERIC;
114       } else if ("ORACLE".equalsIgnoreCase(pMode)) {
115         return ORACLE;
116       } else {
117         throw new IllegalArgumentException JavaDoc("Valid database modes are either of 'generic' or 'oracle', not " + pMode);
118       }
119     }
120
121     /** <p>Default database mode; types are taken as reported by the JDBC
122      * driver.</p>
123      */

124     public static final Mode GENERIC = new Mode("Generic");
125     /** <p>Oracle database mode; the type NUMERIC is interpreted as FLOAT,
126      * TINYINT, SMALLINT, INTEGER, BIGINT, or DOUBLE, depending on scale
127      * and precision. This mode is turned on by setting the option
128      * <code>jdbc.dbmode</code> or if the method
129      * {@link java.sql.DatabaseMetaData#getDatabaseProductName()}
130      * returns the value "Oracle".</p>
131      */

132     public static final Mode ORACLE = new Mode("Oracle");
133   }
134
135   private class JdbcAttribute implements XSAttribute {
136     private final Locator JavaDoc locator;
137     private final XsQName name;
138     private final XSType type;
139     private final boolean isOptional;
140     private final XSObject parent;
141
142     /** An attribute, which matches a database column.
143      */

144     public JdbcAttribute(XSObject pParent, Locator JavaDoc pLocator, XsQName pName, XSType pType, boolean pOptional) {
145       parent = pParent;
146       locator = pLocator;
147       name = pName;
148       type = pType;
149       isOptional = pOptional;
150     }
151
152     public boolean isGlobal() { return false; }
153     /** For compatibility only: The value true is unsupported.
154      * @throws IllegalStateException An attempt was made, to make the
155      * attribute public.
156      */

157     public void setGlobal(boolean pGlobal) {
158       if (!pGlobal) {
159         throw new IllegalStateException JavaDoc("This attribute cannot be made global");
160       }
161     }
162     public XsQName getName() { return name; }
163     public XSType getType() { return type; }
164     public boolean isOptional() { return isOptional; }
165     public XSAnnotation[] getAnnotations() { return new XSAnnotation[0]; }
166     public Locator JavaDoc getLocator() { return locator; }
167     public void validate() throws SAXException {}
168     public boolean isTopLevelObject() { return false; }
169     public XSObject getParentObject() { return parent; }
170     public XSSchema getXSSchema() { return parent.getXSSchema(); }
171
172     public String JavaDoc getDefault() { return null; }
173     public String JavaDoc getFixed() { return null; }
174     public Attributes JavaDoc getOpenAttributes() { return null; }
175   }
176
177   /** <p>Namespace URI of the JDBC schema writer.</p>
178    */

179   public static final String JavaDoc JAXME_JDBC_SCHEMA_URI = "http://ws.apache.org/jaxme/namespaces/jaxme2/jdbc-mapping";
180
181   private SGFactory sgFactory;
182   private SQLFactory sqlFactory;
183   private String JavaDoc key;
184
185   /** Creates a new instance.
186    */

187   public JaxMeJdbcSG(SGFactoryChain o) {
188     super(o);
189   }
190
191   /** Returns the key, under which the {@link JaxMeJdbcSG} is
192    * registered in the factory.
193    */

194   public String JavaDoc getKey() {
195     return key;
196   }
197
198   public void init(SGFactory pFactory) {
199     super.init(pFactory);
200     sgFactory = pFactory;
201     SchemaReader schemaReader = pFactory.getGenerator().getSchemaReader();
202     if (schemaReader instanceof JaxMeSchemaReader) {
203       JaxMeSchemaReader jaxmeSchemaReader = (JaxMeSchemaReader) schemaReader;
204       jaxmeSchemaReader.addXsObjectCreator(new XsObjectCreator(){
205         public XsObject newBean(XsObject pParent, Locator JavaDoc pLocator, XsQName pQName) throws SAXException {
206             if (pParent instanceof XsEAppinfo) {
207               if (JAXME_JDBC_SCHEMA_URI.equals(pQName.getNamespaceURI())) {
208                 if ("table".equals(pQName.getLocalName())) {
209                   return new TableDetails(JaxMeJdbcSG.this, pParent);
210                 } else if ("connection".equals(pQName.getLocalName())) {
211                   return new ConnectionDetails(JaxMeJdbcSG.this, pParent);
212                 } else {
213                   throw new LocSAXException("Invalid element name: " + pQName, pLocator);
214                 }
215               }
216             }
217             return null;
218           }
219       });
220     } else {
221       throw new IllegalStateException JavaDoc("The schema reader " + schemaReader.getClass().getName() +
222                                        " is not an instance of " + JaxMeSchemaReader.class.getName());
223     }
224
225     String JavaDoc s = schemaReader.getGenerator().getProperty("jdbc.sqlFactory");
226     if (s == null) {
227       sqlFactory = new SQLFactoryImpl();
228     } else {
229       Class JavaDoc c;
230       try {
231         c = ClassLoader.getClass(s, SQLFactory.class);
232       } catch (ClassNotFoundException JavaDoc e) {
233         throw new IllegalStateException JavaDoc("SQLFactory class " + s + ", specified by property jdbc.sqlFactory, not found.");
234       }
235       try {
236         sqlFactory = (SQLFactory) c.newInstance();
237       } catch (InstantiationException JavaDoc e) {
238         throw new IllegalStateException JavaDoc("Unable to instantiate SQLFactory class " + c.getName());
239       } catch (IllegalAccessException JavaDoc e) {
240         throw new IllegalStateException JavaDoc("Illegal access to the default constructor of SQLFactory class " + c.getName());
241       }
242     }
243
244     key = pFactory.getGenerator().getKey();
245   }
246
247   protected SGFactory getSGFactory() {
248     return sgFactory;
249   }
250
251   public Generator getGenerator(SGFactory pFactory) {
252     return super.getGenerator(pFactory);
253   }
254
255   protected Mode getDatabaseMode(ConnectionDetails pDetails,
256                                   Connection JavaDoc pConn) throws SQLException JavaDoc {
257     if (pDetails == null) {
258       String JavaDoc v = pConn.getMetaData().getDatabaseProductName();
259       try {
260         return Mode.valueOf(v);
261       } catch (Exception JavaDoc e) {
262         return Mode.GENERIC;
263       }
264     } else {
265       return pDetails.getDbMode();
266     }
267   }
268
269   /** <p>Guess an SQL type, based on reported type, scale and
270    * precision.</p>
271    */

272   protected int getDbType(Mode pDbMode, int pDbType, long pScale,
273                             long pPrecision, String JavaDoc pDbTypeName) {
274     if (Mode.GENERIC.equals(pDbMode)) {
275       return pDbType;
276     } else if (pDbType == Types.OTHER) {
277       if ("CLOB".equalsIgnoreCase(pDbTypeName)) {
278         return Types.CLOB;
279       } else if ("BLOB".equalsIgnoreCase(pDbTypeName)) {
280         return Types.BLOB;
281       } else {
282         return Types.OTHER;
283       }
284     } else if (pDbType == Types.NUMERIC || "NUMBER".equalsIgnoreCase(pDbTypeName)) {
285       if (pScale == 0) {
286         if (pPrecision == 0) { return Types.FLOAT; }
287         if (pPrecision <= 2) { return Types.TINYINT; }
288         if (pPrecision <= 4) { return Types.SMALLINT; }
289         if (pPrecision <= 9) { return Types.INTEGER; }
290         return Types.BIGINT;
291       } else if (pScale == -127) {
292         // Uses binary precision - See page 4-37 of the OCI book
293
if (pPrecision < 24) {
294           return Types.FLOAT; // 53 is double cutoff
295
}
296       } else {
297         // Uses decimal precision - See page 4-37 of the OCI book
298
if (pPrecision < 8) {
299           return Types.FLOAT; // 15 is double cutoff
300
}
301       }
302     } else if (pDbType != Types.NUMERIC) {
303       return pDbType;
304     }
305     return Types.DOUBLE;
306   }
307
308   /** <p>Creates a new attribute or chooses an existing atomic
309    * child element. Returns the {@link AttributeSG} or
310    * {@link ParticleSG}.</p>
311    */

312   protected Object JavaDoc addColumn(ComplexTypeSG pTypeSG, XSType pType, Column pColumn) throws SAXException {
313     final String JavaDoc mName = "addColumn";
314     log.entering(mName, pColumn.getQName());
315     /* May be there already is an attribute or child element
316      * with default settings?
317      */

318     List JavaDoc allChilds = new ArrayList JavaDoc();
319     AttributeSG[] attributes = pTypeSG.getAttributes();
320     if (attributes != null) {
321       allChilds.addAll(Arrays.asList(attributes));
322     }
323     if (!pTypeSG.hasSimpleContent()) {
324       ComplexContentSG cct = pTypeSG.getComplexContentSG();
325       GroupSG groupSG = cct.getRootParticle().getGroupSG();
326       ParticleSG[] childs = groupSG.getParticles();
327       if (childs != null) {
328         for (int i = 0; i < childs.length; i++) {
329           ParticleSG child = childs[i];
330           // Accept only simple elements
331
if (child.isElement()) {
332             ObjectSG objectSG = child.getObjectSG();
333             if (!objectSG.getTypeSG().isComplex()) {
334               allChilds.add(child);
335             }
336           }
337         }
338       }
339     }
340
341     Object JavaDoc theChild = null;
342     for (Iterator JavaDoc iter = allChilds.iterator(); iter.hasNext(); ) {
343       Object JavaDoc currentChild = iter.next();
344       String JavaDoc localName;
345       if (currentChild instanceof AttributeSG) {
346         localName = ((AttributeSG) currentChild).getName().getLocalName();
347       } else if (currentChild instanceof ParticleSG) {
348         localName = ((ParticleSG) currentChild).getObjectSG().getName().getLocalName();
349       } else {
350         throw new IllegalStateException JavaDoc("Expected either attribute or element.");
351       }
352       if (localName != null && localName.equalsIgnoreCase(pColumn.getName().getName())) {
353         if (theChild == null) {
354           theChild = currentChild;
355         } else {
356           log.warn(mName, "Multiple matching attributes or child elements found for column " +
357                    pColumn.getQName());
358         }
359       }
360     }
361
362     if (theChild == null) {
363       // We have to create a new attribute matching the column
364
XSType xsType;
365       if (pColumn.isBinaryColumn()) {
366         xsType = XSBase64Binary.getInstance();
367       } else if (pColumn.isStringColumn()) {
368         xsType = XSString.getInstance();
369       } else {
370         Column.Type myType = pColumn.getType();
371         if (Column.Type.BIT.equals(myType)) {
372           xsType = XSBoolean.getInstance();
373         } else if (Column.Type.DATE.equals(myType)) {
374           xsType = XSDate.getInstance();
375         } else if (Column.Type.DOUBLE.equals(myType)) {
376           xsType = XSDouble.getInstance();
377         } else if (Column.Type.FLOAT.equals(myType)) {
378           xsType = XSFloat.getInstance();
379         } else if (Column.Type.SMALLINT.equals(myType)) {
380           xsType = XSShort.getInstance();
381         } else if (Column.Type.TIME.equals(myType)) {
382           xsType = XSTime.getInstance();
383         } else if (Column.Type.TIMESTAMP.equals(myType)) {
384           xsType = XSDateTime.getInstance();
385         } else if (Column.Type.TINYINT.equals(myType)) {
386           xsType = XSByte.getInstance();
387         } else if (Column.Type.INTEGER.equals(myType)) {
388           xsType = XSInt.getInstance();
389         } else {
390           throw new IllegalStateException JavaDoc("Unknown column type: " + myType);
391         }
392       }
393
394       XSAttribute attr = new JdbcAttribute(pType, pType.getLocator(),
395                                            new XsQName((String JavaDoc) null, pColumn.getName().getName()), xsType,
396                                            pColumn.isNullable());
397       AttributeSGChain chain = (AttributeSGChain) pTypeSG.newAttributeSG(attr);
398       AttributeSG attributeSG = new AttributeSGImpl(chain);
399       pTypeSG.addAttributeSG(attributeSG);
400       theChild = attributeSG;
401     }
402
403     return theChild;
404   }
405
406   /** <p>We use the interface Connector in order to allow people use of this
407    * class, even if they don't have the javax.sql package around.</p>
408    */

409   private interface Connector {
410     /** Returns a new database connection.
411      */

412     public Connection JavaDoc getConnection(TableDetails pDetails) throws SAXException;
413   }
414
415   private class DriverManagerConnector implements Connector {
416     public Connection JavaDoc getConnection(TableDetails pTableDetails) throws SAXException {
417       final String JavaDoc mName = "DriverManagerConnector.getConnection";
418       Class JavaDoc c = null;
419       Exception JavaDoc ex = null;
420       log.fine(mName, "Loading driver " + pTableDetails.getDriver());
421       try {
422         Class.forName(pTableDetails.getDriver());
423       } catch (Exception JavaDoc e) {
424       }
425       if (c == null) {
426         try {
427           java.lang.ClassLoader JavaDoc cl = Thread.currentThread().getContextClassLoader();
428           if (cl == null) {
429             cl = getClass().getClassLoader();
430           }
431           c = cl.loadClass(pTableDetails.getDriver());
432         } catch (Exception JavaDoc e) {
433           if (ex == null) { ex = e; }
434         }
435       }
436       if (c == null) {
437         if (ex == null) { ex = new ClassNotFoundException JavaDoc(); }
438         throw new LocSAXException("Unable to load driver class " + pTableDetails.getDriver()
439                                    + ": " + ex.getClass().getName() + ", " + ex.getMessage(),
440                                    pTableDetails.getLocator());
441       }
442       log.fine(mName, "Connecting to database " + pTableDetails.getUrl() + " as " + pTableDetails.getUser());
443       try {
444         Connection JavaDoc conn = DriverManager.getConnection(pTableDetails.getUrl(), pTableDetails.getUser(),
445                                                       pTableDetails.getPassword());
446         if (conn == null) {
447           throw new LocSAXException("Unable to connect to " + pTableDetails.getUrl()
448                                      + " as user " + pTableDetails.getUser()
449                                      + ": DriverManager returned a null connection",
450                                      pTableDetails.getLocator());
451         }
452         return conn;
453       } catch (SQLException JavaDoc e) {
454         throw new LocSAXException("Unable to connect to " + pTableDetails.getUrl()
455                                    + " as user " + pTableDetails.getUser()
456                                    + ": SQL State = " + e.getSQLState() + ", error code = "
457                                    + e.getErrorCode() + ", " + e.getMessage(),
458                                    pTableDetails.getLocator(), e);
459       }
460     }
461   }
462
463   private class DatasourceConnector implements Connector {
464     public Connection JavaDoc getConnection(TableDetails pTableDetails) throws SAXException {
465       javax.naming.InitialContext JavaDoc ic;
466       try {
467         ic = new javax.naming.InitialContext JavaDoc();
468       } catch (NamingException JavaDoc e) {
469         throw new LocSAXException("Failed to create initial JNDI context: "
470                                    + e.getClass().getName() + ", " + e.getMessage(),
471                                    pTableDetails.getLocator(), e);
472       }
473       javax.sql.DataSource JavaDoc ds;
474       try {
475         ds = (javax.sql.DataSource JavaDoc) ic.lookup(pTableDetails.getDatasource());
476       } catch (NamingException JavaDoc e) {
477         throw new LocSAXException("Failed to lookup datasource " + pTableDetails.getDatasource()
478                                    + ": " + e.getClass().getName() + ", " + e.getMessage(),
479                                    pTableDetails.getLocator(), e);
480       }
481       try {
482         Connection JavaDoc conn = ds.getConnection(pTableDetails.getUser(), pTableDetails.getPassword());
483         if (conn == null) {
484           throw new LocSAXException("Unable to connect to " + pTableDetails.getUrl()
485                                      + " as user " + pTableDetails.getUser()
486                                      + ": Datasource returned a null connection",
487                                      pTableDetails.getLocator());
488         }
489         return conn;
490       } catch (SQLException JavaDoc e) {
491         throw new LocSAXException("Unable to connect to datasource " + pTableDetails.getUrl()
492                                    + " as user " + pTableDetails.getUser()
493                                    + ": SQL State = " + e.getSQLState() + ", error code = "
494                                    + e.getErrorCode() + ", " + e.getMessage(),
495                                    pTableDetails.getLocator(), e);
496       }
497     }
498   }
499
500   protected CustomTableData addTableData(ComplexTypeSG pTypeSG, XSType pType,
501                                           TableDetails pTableDetails) throws SAXException {
502     final String JavaDoc mName = "addTableData";
503     log.entering(mName, new Object JavaDoc[]{pTypeSG, pTableDetails});
504     String JavaDoc tableName = pTableDetails.getName();
505
506     Connection JavaDoc conn;
507     if (pTableDetails.getDriver() == null) {
508       conn = new DatasourceConnector().getConnection(pTableDetails);
509     } else {
510       conn = new DriverManagerConnector().getConnection(pTableDetails);
511     }
512
513     try {
514       int offset = tableName.indexOf('.');
515       String JavaDoc schemaName;
516       if (offset > 0) {
517         schemaName = tableName.substring(0, offset);
518         tableName = tableName.substring(offset+1);
519       } else {
520         schemaName = null;
521       }
522       Table table;
523       try {
524         table = sqlFactory.getTable(conn, schemaName, tableName);
525         conn.close();
526         conn = null;
527       } catch (SQLException JavaDoc e) {
528         throw new SAXException("Failed to read table " + pTableDetails.getName() + ": " + e.getMessage(), e);
529       }
530       if (table.getPrimaryKey() == null) {
531         throw new IllegalStateException JavaDoc("The table " + table.getQName() + " does not have a primary key.");
532       }
533       CustomTableData customTableData = new CustomTableData(this, table, pTypeSG, pTableDetails);
534       for (Iterator JavaDoc iter = table.getColumns(); iter.hasNext(); ) {
535         Column col = (Column) iter.next();
536         Object JavaDoc sg = addColumn(pTypeSG, pType, col);
537         CustomColumnData colData = new CustomColumnData(col.getName().getName(), sg);
538         col.setCustomData(colData);
539       }
540
541       return customTableData;
542     } finally {
543       if (conn != null) { try { conn.close(); } catch (Throwable JavaDoc ignore) {} }
544     }
545   }
546
547   public Object JavaDoc newTypeSG(SGFactory pController, XSType pType) throws SAXException {
548     return new JdbcTypeSG(this, (TypeSGChain) super.newTypeSG(pController, pType), pType);
549   }
550
551   public Object JavaDoc newTypeSG(SGFactory pController, XSType pType, XsQName pName) throws SAXException {
552     return new JdbcTypeSG(this, (TypeSGChain) super.newTypeSG(pController, pType, pName), pType);
553   }
554
555   public Object JavaDoc newTypeSG(SGFactory pController, XSType pType, Context pClassContext, XsQName pName) throws SAXException {
556     return new JdbcTypeSG(this, (TypeSGChain) super.newTypeSG(pController, pType, pClassContext, pName), pType);
557   }
558
559   public Object JavaDoc newSchemaSG(SGFactory pController, XSSchema pSchema) throws SAXException {
560     SchemaSGChain chain = (SchemaSGChain) super.newSchemaSG(pController, pSchema);
561     chain = new JdbcSchemaSG(this, chain);
562     return chain;
563   }
564 }
565
Popular Tags