1 17 package org.apache.ws.jaxme.pm.generator.jdbc; 18 19 import java.sql.Connection ; 20 import java.sql.DriverManager ; 21 import java.sql.SQLException ; 22 import java.sql.Types ; 23 import java.util.ArrayList ; 24 import java.util.Arrays ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 28 import javax.naming.NamingException ; 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 ; 76 import org.xml.sax.Locator ; 77 import org.xml.sax.SAXException ; 78 79 80 85 public class JaxMeJdbcSG extends SGFactoryChainImpl { 86 Logger log = LoggerAccess.getLogger(JaxMeJdbcSG.class); 87 88 92 public static class Mode { 93 private String name; 94 private Mode(String pName) { name = pName; } 95 public String toString() { return name; } 96 98 public String getName() { return name; } 99 public int hashCode() { return name.hashCode(); } 100 public boolean equals(Object o) { 101 if (o == null || !(o instanceof Mode)) { 102 return false; 103 } else { 104 return name.equals(((Mode) o).name); 105 } 106 } 107 111 public static Mode valueOf(String pMode) { 112 if ("GENERIC".equalsIgnoreCase(pMode)) { 113 return GENERIC; 114 } else if ("ORACLE".equalsIgnoreCase(pMode)) { 115 return ORACLE; 116 } else { 117 throw new IllegalArgumentException ("Valid database modes are either of 'generic' or 'oracle', not " + pMode); 118 } 119 } 120 121 124 public static final Mode GENERIC = new Mode("Generic"); 125 132 public static final Mode ORACLE = new Mode("Oracle"); 133 } 134 135 private class JdbcAttribute implements XSAttribute { 136 private final Locator locator; 137 private final XsQName name; 138 private final XSType type; 139 private final boolean isOptional; 140 private final XSObject parent; 141 142 144 public JdbcAttribute(XSObject pParent, Locator 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 157 public void setGlobal(boolean pGlobal) { 158 if (!pGlobal) { 159 throw new IllegalStateException ("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 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 getDefault() { return null; } 173 public String getFixed() { return null; } 174 public Attributes getOpenAttributes() { return null; } 175 } 176 177 179 public static final String 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 key; 184 185 187 public JaxMeJdbcSG(SGFactoryChain o) { 188 super(o); 189 } 190 191 194 public String 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 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 ("The schema reader " + schemaReader.getClass().getName() + 222 " is not an instance of " + JaxMeSchemaReader.class.getName()); 223 } 224 225 String s = schemaReader.getGenerator().getProperty("jdbc.sqlFactory"); 226 if (s == null) { 227 sqlFactory = new SQLFactoryImpl(); 228 } else { 229 Class c; 230 try { 231 c = ClassLoader.getClass(s, SQLFactory.class); 232 } catch (ClassNotFoundException e) { 233 throw new IllegalStateException ("SQLFactory class " + s + ", specified by property jdbc.sqlFactory, not found."); 234 } 235 try { 236 sqlFactory = (SQLFactory) c.newInstance(); 237 } catch (InstantiationException e) { 238 throw new IllegalStateException ("Unable to instantiate SQLFactory class " + c.getName()); 239 } catch (IllegalAccessException e) { 240 throw new IllegalStateException ("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 pConn) throws SQLException { 257 if (pDetails == null) { 258 String v = pConn.getMetaData().getDatabaseProductName(); 259 try { 260 return Mode.valueOf(v); 261 } catch (Exception e) { 262 return Mode.GENERIC; 263 } 264 } else { 265 return pDetails.getDbMode(); 266 } 267 } 268 269 272 protected int getDbType(Mode pDbMode, int pDbType, long pScale, 273 long pPrecision, String 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 if (pPrecision < 24) { 294 return Types.FLOAT; } 296 } else { 297 if (pPrecision < 8) { 299 return Types.FLOAT; } 301 } 302 } else if (pDbType != Types.NUMERIC) { 303 return pDbType; 304 } 305 return Types.DOUBLE; 306 } 307 308 312 protected Object addColumn(ComplexTypeSG pTypeSG, XSType pType, Column pColumn) throws SAXException { 313 final String mName = "addColumn"; 314 log.entering(mName, pColumn.getQName()); 315 318 List allChilds = new ArrayList (); 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 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 theChild = null; 342 for (Iterator iter = allChilds.iterator(); iter.hasNext(); ) { 343 Object currentChild = iter.next(); 344 String 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 ("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 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 ("Unknown column type: " + myType); 391 } 392 } 393 394 XSAttribute attr = new JdbcAttribute(pType, pType.getLocator(), 395 new XsQName((String ) 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 409 private interface Connector { 410 412 public Connection getConnection(TableDetails pDetails) throws SAXException; 413 } 414 415 private class DriverManagerConnector implements Connector { 416 public Connection getConnection(TableDetails pTableDetails) throws SAXException { 417 final String mName = "DriverManagerConnector.getConnection"; 418 Class c = null; 419 Exception ex = null; 420 log.fine(mName, "Loading driver " + pTableDetails.getDriver()); 421 try { 422 Class.forName(pTableDetails.getDriver()); 423 } catch (Exception e) { 424 } 425 if (c == null) { 426 try { 427 java.lang.ClassLoader cl = Thread.currentThread().getContextClassLoader(); 428 if (cl == null) { 429 cl = getClass().getClassLoader(); 430 } 431 c = cl.loadClass(pTableDetails.getDriver()); 432 } catch (Exception e) { 433 if (ex == null) { ex = e; } 434 } 435 } 436 if (c == null) { 437 if (ex == null) { ex = new ClassNotFoundException (); } 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 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 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 getConnection(TableDetails pTableDetails) throws SAXException { 465 javax.naming.InitialContext ic; 466 try { 467 ic = new javax.naming.InitialContext (); 468 } catch (NamingException 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 ds; 474 try { 475 ds = (javax.sql.DataSource ) ic.lookup(pTableDetails.getDatasource()); 476 } catch (NamingException 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 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 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 mName = "addTableData"; 503 log.entering(mName, new Object []{pTypeSG, pTableDetails}); 504 String tableName = pTableDetails.getName(); 505 506 Connection 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 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 e) { 528 throw new SAXException("Failed to read table " + pTableDetails.getName() + ": " + e.getMessage(), e); 529 } 530 if (table.getPrimaryKey() == null) { 531 throw new IllegalStateException ("The table " + table.getQName() + " does not have a primary key."); 532 } 533 CustomTableData customTableData = new CustomTableData(this, table, pTypeSG, pTableDetails); 534 for (Iterator iter = table.getColumns(); iter.hasNext(); ) { 535 Column col = (Column) iter.next(); 536 Object 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 ignore) {} } 544 } 545 } 546 547 public Object newTypeSG(SGFactory pController, XSType pType) throws SAXException { 548 return new JdbcTypeSG(this, (TypeSGChain) super.newTypeSG(pController, pType), pType); 549 } 550 551 public Object 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 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 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 |