001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.converter.bea; 018 019 import java.io.Reader; 020 import java.io.IOException; 021 import java.io.StringReader; 022 import java.util.List; 023 import java.util.ArrayList; 024 import java.util.Map; 025 import java.util.HashMap; 026 import java.util.Properties; 027 import java.util.Iterator; 028 import javax.xml.parsers.DocumentBuilderFactory; 029 import javax.xml.parsers.DocumentBuilder; 030 import javax.xml.parsers.ParserConfigurationException; 031 import org.apache.geronimo.converter.DOMUtils; 032 import org.apache.geronimo.converter.DatabaseConversionStatus; 033 import org.apache.geronimo.converter.JDBCPool; 034 import org.apache.geronimo.converter.XADatabasePool; 035 import org.apache.geronimo.converter.AbstractDatabasePool; 036 import org.apache.geronimo.kernel.util.XmlUtil; 037 import org.w3c.dom.Document; 038 import org.w3c.dom.Element; 039 import org.w3c.dom.NodeList; 040 import org.w3c.dom.Node; 041 import org.xml.sax.InputSource; 042 import org.xml.sax.SAXException; 043 044 /** 045 * Converts database pools from WebLogic 8.1 to Geronimo 046 * 047 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 048 */ 049 public class WebLogic81DatabaseConverter extends DOMUtils { 050 public static DatabaseConversionStatus convert(String libDir, String domainDir) throws IOException { 051 Weblogic81Utils utils = new Weblogic81Utils(libDir, domainDir); 052 String config = utils.getConfigXML(); 053 return convert(new StringReader(config)); 054 } 055 056 public static DatabaseConversionStatus convert(Reader configXml) throws IOException { 057 List status = new ArrayList(); 058 List noTx = new ArrayList(); 059 List local = new ArrayList(); 060 List xa = new ArrayList(); 061 062 DocumentBuilderFactory factory = XmlUtil.newDocumentBuilderFactory(); 063 factory.setValidating(false); 064 try { 065 DocumentBuilder builder = factory.newDocumentBuilder(); 066 Document doc = builder.parse(new InputSource(configXml)); 067 configXml.close(); 068 parseDocument(doc, status, local, xa); 069 } catch (ParserConfigurationException e) { 070 throw (IOException)new IOException().initCause(e); 071 } catch (SAXException e) { 072 throw (IOException)new IOException().initCause(e); 073 } 074 075 DatabaseConversionStatus result = new DatabaseConversionStatus(); 076 result.setMessages((String[]) status.toArray(new String[status.size()])); 077 result.setNoTXPools((JDBCPool[]) noTx.toArray(new JDBCPool[noTx.size()])); 078 result.setJdbcPools((JDBCPool[]) local.toArray(new JDBCPool[noTx.size()])); 079 result.setXaPools((XADatabasePool[]) xa.toArray(new XADatabasePool[xa.size()])); 080 return result; 081 } 082 083 private static void parseDocument(Document doc, List status, List local, List xa) { 084 Element domain = doc.getDocumentElement(); 085 if(!domain.getNodeName().equalsIgnoreCase("Domain")) { 086 status.add("ERROR: Unrecognized file beginning with "+domain.getNodeName()+" element. Expected a WebLogic config.xml file."); 087 return; 088 } 089 NodeList list = domain.getChildNodes(); 090 Map pools = new HashMap(); 091 for(int i=0; i<list.getLength(); i++) { 092 Node node = list.item(i); 093 if(node.getNodeType() == Node.ELEMENT_NODE) { 094 String name = node.getNodeName(); 095 if(name.equalsIgnoreCase("JDBCConnectionPool")) { 096 ConnectionPool pool = getConnectionPool((Element)node, status); 097 pools.put(pool.getName(), pool); 098 } else if(name.equalsIgnoreCase("JDBCDataSource")) { 099 DataSource ds = getDataSource((Element)node, false); 100 ConnectionPool pool = (ConnectionPool) pools.get(ds.getPoolName()); 101 if(pool != null) { 102 pool.getDataSources().add(ds); 103 } else { 104 status.add("ERROR: Can't find pool for data source '"+ds.getName()+"' ("+ds.getPoolName()+")"); 105 } 106 } else if(name.equalsIgnoreCase("JDBCTxDataSource")) { 107 DataSource ds = getDataSource((Element)node, true); 108 ConnectionPool pool = (ConnectionPool) pools.get(ds.getPoolName()); 109 if(pool != null) { 110 pool.getDataSources().add(ds); 111 } else { 112 status.add("ERROR: Can't find pool for data source '"+ds.getName()+"' ("+ds.getPoolName()+")"); 113 } 114 } else { 115 status.add("Skipping element '"+name+"'"); 116 } 117 } 118 } 119 if(pools.size() > 0) { 120 for (Iterator it = pools.values().iterator(); it.hasNext();) { 121 ConnectionPool pool = (ConnectionPool) it.next(); 122 if(pool.getPassword() != null && pool.getPassword().startsWith("{")) { 123 status.add("NOTE: When importing from WebLogic, typically database passwords cannot be recovered, and will need to be re-entered."); 124 break; 125 } 126 } 127 } 128 processPools((ConnectionPool[]) pools.values().toArray(new ConnectionPool[0]), 129 status, local, xa); 130 } 131 132 private static void processPools(ConnectionPool[] pools, List status, List local, List xa) { 133 for (int i = 0; i < pools.length; i++) { 134 ConnectionPool pool = pools[i]; 135 boolean isXA; 136 if(pool.hasEmulate()) { 137 isXA = false; 138 } else if(pool.hasNonTX()) { 139 isXA = false; 140 } else if(pool.hasXADriverName()) { 141 isXA = true; 142 } else { 143 isXA = false; 144 status.add("Can't tell whether pool '"+pool.getName()+"' is an XA driver or not; will create local transaction pools in Geronimo."); 145 } 146 if(pool.getDataSources().size() == 0) { 147 status.add("Pool '"+pool.getName()+"' has no associated data sources. Creating a default pool for it."); 148 if(isXA) { 149 xa.add(createXAPool(pool, pool.getName(), null)); 150 } else { 151 local.add(createJDBCPool(pool, pool.getName(), null)); 152 } 153 } else { 154 for (int j = 0; j < pool.getDataSources().size(); j++) { 155 DataSource ds = (DataSource) pool.getDataSources().get(j); 156 if(isXA) { 157 xa.add(createXAPool(pool, ds.getName(), ds.getJndiName())); 158 } else { 159 local.add(createJDBCPool(pool, ds.getName(), ds.getJndiName())); 160 } 161 } 162 } 163 } 164 } 165 166 private static void populatePool(ConnectionPool pool, AbstractDatabasePool target) { 167 if(pool.getReserveTimeoutSecs() != null) { 168 target.setBlockingTimeoutMillis(new Integer(pool.getReserveTimeoutSecs().intValue()*1000)); 169 } 170 if(pool.getIdleTimeoutSecs() != null) { 171 target.setIdleTimeoutMillis(new Integer(pool.getIdleTimeoutSecs().intValue()*1000)); 172 } 173 target.setMaxSize(pool.getMax()); 174 target.setMinSize(pool.getMin()); 175 target.setNewConnectionSQL(pool.getInitSQL()); 176 target.setStatementCacheSize(pool.getCacheSize()); 177 target.setTestConnectionSQL(pool.getTestTable() == null ? null : "SELECT * FROM "+pool.getTestTable()+" WHERE 0=1"); 178 if(pool.getDriverName().toLowerCase().indexOf("oracle") > -1) target.setVendor(JDBCPool.VENDOR_ORACLE); 179 if(pool.getDriverName().toLowerCase().indexOf("mysql") > -1) target.setVendor(JDBCPool.VENDOR_MYSQL); 180 if(pool.getDriverName().toLowerCase().indexOf("sybase") > -1) target.setVendor(JDBCPool.VENDOR_SYBASE); 181 if(pool.getDriverName().toLowerCase().indexOf("informix") > -1) target.setVendor(JDBCPool.VENDOR_INFORMIX); 182 } 183 184 private static JDBCPool createJDBCPool(ConnectionPool pool, String name, String jndiName) { 185 JDBCPool result = new JDBCPool(); 186 result.setName(name); 187 result.setJndiName(jndiName); 188 populatePool(pool, result); 189 result.setConnectionProperties(pool.getProperties()); 190 result.setDriverClass(pool.getDriverName()); 191 result.setJdbcURL(pool.getUrl()); 192 // Don't bother putting encrypted passwords into the pool 193 if(pool.getPassword() != null && !pool.getPassword().startsWith("{")) { 194 result.setPassword(pool.getPassword()); 195 } 196 result.setUsername(pool.getUsername()); 197 return result; 198 } 199 200 private static XADatabasePool createXAPool(ConnectionPool pool, String name, String jndiName) { 201 XADatabasePool result = new XADatabasePool(); 202 result.setName(name); 203 result.setJndiName(jndiName); 204 populatePool(pool, result); 205 result.setXaDataSourceClass(pool.getDriverName()); 206 result.setProperties(pool.getProperties()); 207 return result; 208 } 209 210 private static DataSource getDataSource(Element root, boolean tx) { 211 DataSource ds = new DataSource(); 212 ds.setDeclaredAsTX(tx); 213 ds.setEmulate(getBoolean(root.getAttribute("EnableTwoPhaseCommit"), false)); 214 ds.setName(root.getAttribute("Name")); 215 ds.setJndiName(root.getAttribute("JNDIName")); 216 ds.setPoolName(root.getAttribute("PoolName")); 217 return ds; 218 } 219 220 private static boolean getBoolean(String value, boolean defaultResult) { 221 if(value == null) { 222 return defaultResult; 223 } 224 return new Boolean(value).booleanValue(); 225 } 226 227 private static ConnectionPool getConnectionPool(Element root, List status) { 228 ConnectionPool pool = new ConnectionPool(); 229 pool.setName(root.getAttribute("Name")); 230 pool.setDriverName(root.getAttribute("DriverName")); 231 pool.setUrl(root.getAttribute("URL")); 232 pool.setMin(getInteger(root.getAttribute("InitialCapacity"))); 233 pool.setMax(getInteger(root.getAttribute("MaxCapacity"))); 234 readProperties(pool.getProperties(), root.getAttribute("Properties"), status); 235 pool.setUsername(pool.getProperties().getProperty("user")); 236 pool.getProperties().remove("user"); 237 if(root.hasAttribute("Password")) { 238 pool.setPassword(root.getAttribute("Password")); 239 } else if(root.hasAttribute("PasswordEncrypted")) { 240 pool.setPassword(root.getAttribute("PasswordEncrypted")); 241 } 242 pool.setReserveTimeoutSecs(getInteger(root.getAttribute("ConnectionReserveTimeoutSeconds"))); 243 pool.setIdleTimeoutSecs(getInteger(root.getAttribute("InactiveConnectionTimeoutSeconds"))); 244 pool.setCacheSize(getInteger(root.getAttribute("StatementCacheSize"))); 245 pool.setInitSQL(root.getAttribute("InitSQL")); 246 pool.setTestTable(root.getAttribute("TestTableName")); 247 return pool; 248 } 249 250 private static void readProperties(Properties props, String value, List status) { 251 if(value == null) { 252 return; 253 } 254 value = value.trim(); 255 if(value.equals("")) { 256 return; 257 } 258 int last = -1; 259 int pos = value.indexOf(';'); 260 while(pos > -1) { 261 String s = value.substring(last+1, pos); 262 int eq = s.indexOf('='); 263 if(eq > -1) { 264 props.setProperty(s.substring(0, eq), s.substring(eq+1)); 265 } else { 266 status.add("WARN: Unable to read property '"+s+"'"); 267 } 268 last = pos; 269 pos = value.indexOf(';', pos+1); 270 } 271 String s = value.substring(last+1); 272 int eq = s.indexOf('='); 273 if(eq > -1) { 274 props.setProperty(s.substring(0, eq), s.substring(eq+1)); 275 } else { 276 status.add("WARN: Unable to read property '"+s+"'"); 277 } 278 } 279 280 private static Integer getInteger(String value) { 281 if(value == null) { 282 return null; 283 } 284 value = value.trim(); 285 if(value.equals("")) { 286 return null; 287 } 288 return new Integer(value); 289 } 290 291 public static class DataSource { 292 private String name; 293 private String poolName; 294 private String jndiName; 295 private boolean emulate; 296 private boolean declaredAsTX; 297 298 public String getName() { 299 return name; 300 } 301 302 public void setName(String name) { 303 this.name = name; 304 } 305 306 public String getPoolName() { 307 return poolName; 308 } 309 310 public void setPoolName(String poolName) { 311 this.poolName = poolName; 312 } 313 314 public String getJndiName() { 315 return jndiName; 316 } 317 318 public void setJndiName(String jndiName) { 319 this.jndiName = jndiName; 320 } 321 322 public boolean isEmulate() { 323 return emulate; 324 } 325 326 public void setEmulate(boolean emulate) { 327 this.emulate = emulate; 328 } 329 330 public boolean isDeclaredAsTX() { 331 return declaredAsTX; 332 } 333 334 public void setDeclaredAsTX(boolean declaredAsTX) { 335 this.declaredAsTX = declaredAsTX; 336 } 337 } 338 339 public static class ConnectionPool { 340 private String name; 341 private String driverName; 342 private Integer min, max; 343 private String url; 344 private String username; 345 private String password; 346 private Integer reserveTimeoutSecs; 347 private Integer idleTimeoutSecs; 348 private Integer cacheSize; 349 private String initSQL; 350 private String testTable; 351 private Properties properties = new Properties(); 352 private List dataSources = new ArrayList(); 353 354 public boolean hasEmulate() { 355 for (int i = 0; i < dataSources.size(); i++) { 356 DataSource ds = (DataSource) dataSources.get(i); 357 if(ds.isEmulate()) { 358 return true; 359 } 360 } 361 return false; 362 } 363 364 public boolean hasNonTX() { 365 for (int i = 0; i < dataSources.size(); i++) { 366 DataSource ds = (DataSource) dataSources.get(i); 367 if(!ds.isDeclaredAsTX()) { 368 return true; 369 } 370 } 371 return false; 372 } 373 374 public boolean hasXADriverName() { 375 return driverName.toUpperCase().indexOf("XA") > -1; 376 } 377 378 public String getName() { 379 return name; 380 } 381 382 public void setName(String name) { 383 this.name = name; 384 } 385 386 public String getDriverName() { 387 return driverName; 388 } 389 390 public void setDriverName(String driverName) { 391 this.driverName = driverName; 392 } 393 394 public String getUsername() { 395 return username; 396 } 397 398 public void setUsername(String username) { 399 this.username = username; 400 } 401 402 public String getPassword() { 403 return password; 404 } 405 406 public void setPassword(String password) { 407 this.password = password; 408 } 409 410 public String getInitSQL() { 411 return initSQL; 412 } 413 414 public void setInitSQL(String initSQL) { 415 this.initSQL = initSQL; 416 } 417 418 public String getTestTable() { 419 return testTable; 420 } 421 422 public void setTestTable(String testTable) { 423 this.testTable = testTable; 424 } 425 426 public Properties getProperties() { 427 return properties; 428 } 429 430 public void setProperties(Properties properties) { 431 this.properties = properties; 432 } 433 434 public List getDataSources() { 435 return dataSources; 436 } 437 438 public void setDataSources(List dataSources) { 439 this.dataSources = dataSources; 440 } 441 442 public Integer getMin() { 443 return min; 444 } 445 446 public void setMin(Integer min) { 447 this.min = min; 448 } 449 450 public Integer getMax() { 451 return max; 452 } 453 454 public void setMax(Integer max) { 455 this.max = max; 456 } 457 458 public Integer getReserveTimeoutSecs() { 459 return reserveTimeoutSecs; 460 } 461 462 public void setReserveTimeoutSecs(Integer reserveTimeoutSecs) { 463 this.reserveTimeoutSecs = reserveTimeoutSecs; 464 } 465 466 public Integer getIdleTimeoutSecs() { 467 return idleTimeoutSecs; 468 } 469 470 public void setIdleTimeoutSecs(Integer idleTimeoutSecs) { 471 this.idleTimeoutSecs = idleTimeoutSecs; 472 } 473 474 public Integer getCacheSize() { 475 return cacheSize; 476 } 477 478 public void setCacheSize(Integer cacheSize) { 479 this.cacheSize = cacheSize; 480 } 481 482 public String getUrl() { 483 return url; 484 } 485 486 public void setUrl(String url) { 487 this.url = url; 488 } 489 } 490 }