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.console.databasemanager.wizard; 018 019 import java.io.BufferedOutputStream; 020 import java.io.ByteArrayOutputStream; 021 import java.io.File; 022 import java.io.FileOutputStream; 023 import java.io.FileReader; 024 import java.io.IOException; 025 import java.io.PrintWriter; 026 import java.io.Serializable; 027 import java.io.StringReader; 028 import java.io.StringWriter; 029 import java.io.UnsupportedEncodingException; 030 import java.net.MalformedURLException; 031 import java.net.URI; 032 import java.net.URL; 033 import java.net.URLClassLoader; 034 import java.net.URLDecoder; 035 import java.net.URLEncoder; 036 import java.sql.Connection; 037 import java.sql.DatabaseMetaData; 038 import java.sql.Driver; 039 import java.sql.SQLException; 040 import java.util.ArrayList; 041 import java.util.Arrays; 042 import java.util.Collections; 043 import java.util.Comparator; 044 import java.util.HashMap; 045 import java.util.Iterator; 046 import java.util.List; 047 import java.util.Map; 048 import java.util.Properties; 049 import java.util.SortedSet; 050 import javax.enterprise.deploy.model.DDBean; 051 import javax.enterprise.deploy.model.DDBeanRoot; 052 import javax.enterprise.deploy.shared.ModuleType; 053 import javax.enterprise.deploy.spi.DeploymentConfiguration; 054 import javax.enterprise.deploy.spi.DeploymentManager; 055 import javax.enterprise.deploy.spi.Target; 056 import javax.enterprise.deploy.spi.TargetModuleID; 057 import javax.enterprise.deploy.spi.status.ProgressObject; 058 import javax.portlet.ActionRequest; 059 import javax.portlet.ActionResponse; 060 import javax.portlet.PortletConfig; 061 import javax.portlet.PortletException; 062 import javax.portlet.PortletRequest; 063 import javax.portlet.PortletRequestDispatcher; 064 import javax.portlet.PortletSession; 065 import javax.portlet.RenderRequest; 066 import javax.portlet.RenderResponse; 067 import javax.portlet.WindowState; 068 import javax.xml.parsers.DocumentBuilder; 069 import javax.xml.parsers.DocumentBuilderFactory; 070 import org.apache.commons.fileupload.FileItem; 071 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 072 import org.apache.commons.fileupload.portlet.PortletFileUpload; 073 import org.apache.commons.logging.Log; 074 import org.apache.commons.logging.LogFactory; 075 import org.apache.geronimo.connector.deployment.jsr88.ConfigPropertySetting; 076 import org.apache.geronimo.connector.deployment.jsr88.ConnectionDefinition; 077 import org.apache.geronimo.connector.deployment.jsr88.ConnectionDefinitionInstance; 078 import org.apache.geronimo.connector.deployment.jsr88.ConnectionManager; 079 import org.apache.geronimo.connector.deployment.jsr88.Connector15DCBRoot; 080 import org.apache.geronimo.connector.deployment.jsr88.ConnectorDCB; 081 import org.apache.geronimo.connector.deployment.jsr88.ResourceAdapter; 082 import org.apache.geronimo.connector.deployment.jsr88.SinglePool; 083 import org.apache.geronimo.connector.outbound.PoolingAttributes; 084 import org.apache.geronimo.console.BasePortlet; 085 import org.apache.geronimo.console.ajax.ProgressInfo; 086 import org.apache.geronimo.console.util.PortletManager; 087 import org.apache.geronimo.converter.DatabaseConversionStatus; 088 import org.apache.geronimo.converter.JDBCPool; 089 import org.apache.geronimo.converter.bea.WebLogic81DatabaseConverter; 090 import org.apache.geronimo.converter.jboss.JBoss4DatabaseConverter; 091 import org.apache.geronimo.deployment.service.jsr88.EnvironmentData; 092 import org.apache.geronimo.deployment.tools.loader.ConnectorDeployable; 093 import org.apache.geronimo.gbean.AbstractName; 094 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 095 import org.apache.geronimo.kernel.management.State; 096 import org.apache.geronimo.kernel.proxy.GeronimoManagedBean; 097 import org.apache.geronimo.kernel.repository.Artifact; 098 import org.apache.geronimo.kernel.repository.FileWriteMonitor; 099 import org.apache.geronimo.kernel.repository.ListableRepository; 100 import org.apache.geronimo.kernel.repository.WriteableRepository; 101 import org.apache.geronimo.kernel.util.XmlUtil; 102 import org.apache.geronimo.management.geronimo.JCAManagedConnectionFactory; 103 import org.apache.geronimo.management.geronimo.ResourceAdapterModule; 104 import org.w3c.dom.Document; 105 import org.w3c.dom.Element; 106 import org.w3c.dom.Node; 107 import org.w3c.dom.NodeList; 108 import org.xml.sax.InputSource; 109 110 /** 111 * A portlet that lets you configure and deploy JDBC connection pools. 112 * 113 * @version $Rev: 550963 $ $Date: 2007-06-26 17:38:01 -0400 (Tue, 26 Jun 2007) $ 114 */ 115 public class DatabasePoolPortlet extends BasePortlet { 116 private final static Log log = LogFactory.getLog(DatabasePoolPortlet.class); 117 private final static String[] SKIP_ENTRIES_WITH = new String[]{"geronimo", "tomcat", "tranql", "commons", "directory", "activemq"}; 118 private final static String DRIVER_SESSION_KEY = "org.apache.geronimo.console.dbpool.Drivers"; 119 private final static String CONFIG_SESSION_KEY = "org.apache.geronimo.console.dbpool.ConfigParam"; 120 private final static String DRIVER_INFO_URL = "http://geronimo.apache.org/driver-downloads.properties"; 121 private static final String LIST_VIEW = "/WEB-INF/view/dbwizard/list.jsp"; 122 private static final String EDIT_VIEW = "/WEB-INF/view/dbwizard/edit.jsp"; 123 private static final String SELECT_RDBMS_VIEW = "/WEB-INF/view/dbwizard/selectDatabase.jsp"; 124 private static final String BASIC_PARAMS_VIEW = "/WEB-INF/view/dbwizard/basicParams.jsp"; 125 private static final String CONFIRM_URL_VIEW = "/WEB-INF/view/dbwizard/confirmURL.jsp"; 126 private static final String TEST_CONNECTION_VIEW = "/WEB-INF/view/dbwizard/testConnection.jsp"; 127 private static final String DOWNLOAD_VIEW = "/WEB-INF/view/dbwizard/selectDownload.jsp"; 128 private static final String DOWNLOAD_STATUS_VIEW = "/WEB-INF/view/dbwizard/downloadStatus.jsp"; 129 private static final String SHOW_PLAN_VIEW = "/WEB-INF/view/dbwizard/showPlan.jsp"; 130 private static final String IMPORT_UPLOAD_VIEW = "/WEB-INF/view/dbwizard/importUpload.jsp"; 131 private static final String IMPORT_STATUS_VIEW = "/WEB-INF/view/dbwizard/importStatus.jsp"; 132 private static final String USAGE_VIEW = "/WEB-INF/view/dbwizard/usage.jsp"; 133 private static final String LIST_MODE = "list"; 134 private static final String EDIT_MODE = "edit"; 135 private static final String SELECT_RDBMS_MODE = "rdbms"; 136 private static final String BASIC_PARAMS_MODE = "params"; 137 private static final String CONFIRM_URL_MODE = "url"; 138 private static final String TEST_CONNECTION_MODE = "test"; 139 private static final String SHOW_PLAN_MODE = "plan"; 140 private static final String DOWNLOAD_MODE = "download"; 141 private static final String DOWNLOAD_STATUS_MODE = "downloadStatus"; 142 private static final String EDIT_EXISTING_MODE = "editExisting"; 143 private static final String DELETE_MODE = "delete"; 144 private static final String SAVE_MODE = "save"; 145 private static final String IMPORT_START_MODE = "startImport"; 146 private static final String IMPORT_UPLOAD_MODE = "importUpload"; 147 private static final String IMPORT_STATUS_MODE = "importStatus"; 148 private static final String IMPORT_COMPLETE_MODE = "importComplete"; 149 private static final String WEBLOGIC_IMPORT_MODE = "weblogicImport"; 150 private static final String USAGE_MODE = "usage"; 151 private static final String IMPORT_EDIT_MODE = "importEdit"; 152 private static final String MODE_KEY = "mode"; 153 154 private PortletRequestDispatcher listView; 155 private PortletRequestDispatcher editView; 156 private PortletRequestDispatcher selectRDBMSView; 157 private PortletRequestDispatcher basicParamsView; 158 private PortletRequestDispatcher confirmURLView; 159 private PortletRequestDispatcher testConnectionView; 160 private PortletRequestDispatcher downloadView; 161 private PortletRequestDispatcher downloadStatusView; 162 private PortletRequestDispatcher planView; 163 private PortletRequestDispatcher importUploadView; 164 private PortletRequestDispatcher importStatusView; 165 private PortletRequestDispatcher usageView; 166 167 public void init(PortletConfig portletConfig) throws PortletException { 168 super.init(portletConfig); 169 listView = portletConfig.getPortletContext().getRequestDispatcher(LIST_VIEW); 170 editView = portletConfig.getPortletContext().getRequestDispatcher(EDIT_VIEW); 171 selectRDBMSView = portletConfig.getPortletContext().getRequestDispatcher(SELECT_RDBMS_VIEW); 172 basicParamsView = portletConfig.getPortletContext().getRequestDispatcher(BASIC_PARAMS_VIEW); 173 confirmURLView = portletConfig.getPortletContext().getRequestDispatcher(CONFIRM_URL_VIEW); 174 testConnectionView = portletConfig.getPortletContext().getRequestDispatcher(TEST_CONNECTION_VIEW); 175 downloadView = portletConfig.getPortletContext().getRequestDispatcher(DOWNLOAD_VIEW); 176 downloadStatusView = portletConfig.getPortletContext().getRequestDispatcher(DOWNLOAD_STATUS_VIEW); 177 planView = portletConfig.getPortletContext().getRequestDispatcher(SHOW_PLAN_VIEW); 178 importUploadView = portletConfig.getPortletContext().getRequestDispatcher(IMPORT_UPLOAD_VIEW); 179 importStatusView = portletConfig.getPortletContext().getRequestDispatcher(IMPORT_STATUS_VIEW); 180 usageView = portletConfig.getPortletContext().getRequestDispatcher(USAGE_VIEW); 181 } 182 183 public void destroy() { 184 listView = null; 185 editView = null; 186 selectRDBMSView = null; 187 basicParamsView = null; 188 confirmURLView = null; 189 testConnectionView = null; 190 downloadView = null; 191 downloadStatusView = null; 192 planView = null; 193 importUploadView = null; 194 importStatusView = null; 195 usageView = null; 196 super.destroy(); 197 } 198 199 public DriverDownloader.DriverInfo[] getDriverInfo(PortletRequest request) { 200 PortletSession session = request.getPortletSession(true); 201 DriverDownloader.DriverInfo[] results = (DriverDownloader.DriverInfo[]) session.getAttribute(DRIVER_SESSION_KEY, PortletSession.APPLICATION_SCOPE); 202 if(results == null) { 203 DriverDownloader downloader = new DriverDownloader(); 204 try { 205 results = downloader.loadDriverInfo(new URL(DRIVER_INFO_URL)); 206 session.setAttribute(DRIVER_SESSION_KEY, results, PortletSession.APPLICATION_SCOPE); 207 } catch (MalformedURLException e) { 208 log.error("Unable to download driver data", e); 209 results = new DriverDownloader.DriverInfo[0]; 210 } 211 } 212 return results; 213 } 214 215 /** 216 * Loads data about a resource adapter. Depending on what we already have, may load 217 * the name and description, but always loads the config property descriptions. 218 * @param request Pass it or die 219 * @param rarPath If we're creating a new RA, the path to identify it 220 * @param displayName If we're editing an existing RA, its name 221 * @param adapterAbstractName If we're editing an existing RA, its AbstractName 222 */ 223 public ResourceAdapterParams getRARConfiguration(PortletRequest request, String rarPath, String displayName, String adapterAbstractName) { 224 PortletSession session = request.getPortletSession(true); 225 if(rarPath != null && !rarPath.equals("")) { 226 ResourceAdapterParams results = (ResourceAdapterParams) session.getAttribute(CONFIG_SESSION_KEY+"-"+rarPath, PortletSession.APPLICATION_SCOPE); 227 if(results == null) { 228 results = loadConfigPropertiesByPath(request, rarPath); 229 session.setAttribute(CONFIG_SESSION_KEY+"-"+rarPath, results, PortletSession.APPLICATION_SCOPE); 230 session.setAttribute(CONFIG_SESSION_KEY+"-"+results.displayName, results, PortletSession.APPLICATION_SCOPE); 231 } 232 return results; 233 } else if(displayName != null && !displayName.equals("") && adapterAbstractName != null && !adapterAbstractName.equals("")) { 234 ResourceAdapterParams results = (ResourceAdapterParams) session.getAttribute(CONFIG_SESSION_KEY+"-"+displayName, PortletSession.APPLICATION_SCOPE); 235 if(results == null) { 236 results = loadConfigPropertiesByAbstractName(request, adapterAbstractName); 237 session.setAttribute(CONFIG_SESSION_KEY+"-"+displayName, results, PortletSession.APPLICATION_SCOPE); 238 } 239 return results; 240 } else { 241 throw new IllegalArgumentException(); 242 } 243 } 244 245 public void processAction(ActionRequest actionRequest, 246 ActionResponse actionResponse) throws PortletException, IOException { 247 String mode = actionRequest.getParameter(MODE_KEY); 248 if(mode.equals(IMPORT_UPLOAD_MODE)) { 249 processImportUpload(actionRequest, actionResponse); 250 actionResponse.setRenderParameter(MODE_KEY, IMPORT_STATUS_MODE); 251 return; 252 } 253 PoolData data = new PoolData(); 254 data.load(actionRequest); 255 if(mode.equals("process-"+SELECT_RDBMS_MODE)) { 256 DatabaseDriver info = null; 257 info = getDatabaseInfo(actionRequest, data); 258 if(info != null) { 259 data.rarPath = info.getRAR().toString(); 260 if(info.isXA()) { 261 data.adapterDisplayName="Unknown"; // will pick these up when we process the RA type in the render request 262 data.adapterDescription="Unknown"; 263 actionResponse.setRenderParameter(MODE_KEY, EDIT_MODE); 264 } else { 265 if(data.getDbtype().equals("Other")) { 266 actionResponse.setRenderParameter(MODE_KEY, EDIT_MODE); 267 } else { 268 data.driverClass = info.getDriverClassName(); 269 data.urlPrototype = info.getURLPrototype(); 270 actionResponse.setRenderParameter(MODE_KEY, BASIC_PARAMS_MODE); 271 } 272 } 273 } else { 274 actionResponse.setRenderParameter(MODE_KEY, SELECT_RDBMS_MODE); 275 } 276 } else if(mode.equals("process-"+DOWNLOAD_MODE)) { 277 String name = actionRequest.getParameter("driverName"); 278 DriverDownloader.DriverInfo[] drivers = getDriverInfo(actionRequest); 279 DriverDownloader.DriverInfo found = null; 280 for (int i = 0; i < drivers.length; i++) { 281 DriverDownloader.DriverInfo driver = drivers[i]; 282 if(driver.getName().equals(name)) { 283 found = driver; 284 break; 285 } 286 } 287 if(found != null) { 288 data.jars = new String[] {found.getRepositoryURI()}; 289 WriteableRepository repo = PortletManager.getCurrentServer(actionRequest).getWritableRepositories()[0]; 290 final PortletSession session = actionRequest.getPortletSession(); 291 ProgressInfo progressInfo = new ProgressInfo(); 292 progressInfo.setMainMessage("Downloading " + found.getName()); 293 session.setAttribute(ProgressInfo.PROGRESS_INFO_KEY, progressInfo, PortletSession.APPLICATION_SCOPE); 294 // Start the download monitoring 295 new Thread(new Downloader(found, progressInfo, repo)).start(); 296 actionResponse.setRenderParameter(MODE_KEY, DOWNLOAD_STATUS_MODE); 297 } else { 298 actionResponse.setRenderParameter(MODE_KEY, DOWNLOAD_MODE); 299 } 300 } else if(mode.equals("process-"+DOWNLOAD_STATUS_MODE)) { 301 if(data.getDbtype() == null || data.getDbtype().equals("Other")) { 302 actionResponse.setRenderParameter(MODE_KEY, EDIT_MODE); 303 } else { 304 actionResponse.setRenderParameter(MODE_KEY, BASIC_PARAMS_MODE); 305 } 306 } else if(mode.equals("process-"+BASIC_PARAMS_MODE)) { 307 DatabaseDriver info = null; 308 info = getDatabaseInfo(actionRequest, data); 309 if(info != null) { 310 data.url = populateURL(info.getURLPrototype(), info.getURLParameters(), data.getUrlProperties()); 311 } 312 if(attemptDriverLoad(actionRequest, data) != null) { 313 actionResponse.setRenderParameter(MODE_KEY, CONFIRM_URL_MODE); 314 } else { 315 actionResponse.setRenderParameter("driverError", "Unable to load driver "+data.driverClass); 316 actionResponse.setRenderParameter(MODE_KEY, BASIC_PARAMS_MODE); 317 } 318 } else if(mode.equals("process-"+CONFIRM_URL_MODE)) { 319 String test = actionRequest.getParameter("test"); 320 if(test == null || test.equals("true")) { 321 String result = null; 322 String stack = null; 323 try { 324 result = attemptConnect(actionRequest, data); 325 } catch (Exception e) { 326 StringWriter writer = new StringWriter(); 327 PrintWriter temp = new PrintWriter(writer); 328 e.printStackTrace(temp); 329 temp.flush(); 330 temp.close(); 331 stack = writer.getBuffer().toString(); 332 } 333 if(result != null) actionResponse.setRenderParameter("connectResult", result); 334 actionRequest.getPortletSession(true).setAttribute("connectError", stack); 335 actionResponse.setRenderParameter(MODE_KEY, TEST_CONNECTION_MODE); 336 } else { 337 save(actionRequest, actionResponse, data, false); 338 } 339 } else if(mode.equals(SAVE_MODE)) { 340 save(actionRequest, actionResponse, data, false); 341 } else if(mode.equals(SHOW_PLAN_MODE)) { 342 String plan = save(actionRequest, actionResponse, data, true); 343 actionRequest.getPortletSession(true).setAttribute("deploymentPlan", plan); 344 actionResponse.setRenderParameter(MODE_KEY, SHOW_PLAN_MODE); 345 } else if(mode.equals(EDIT_EXISTING_MODE)) { 346 final String name = actionRequest.getParameter("adapterAbstractName"); 347 loadConnectionFactory(actionRequest, name, data.getAbstractName(), data); 348 actionResponse.setRenderParameter("adapterAbstractName", name); 349 actionResponse.setRenderParameter(MODE_KEY, EDIT_MODE); 350 } else if(mode.equals(SELECT_RDBMS_MODE)) { 351 if(data.getAdapterDisplayName() == null) { // Set a default for a new pool 352 data.adapterDisplayName = "TranQL Generic JDBC Resource Adapter"; 353 } 354 actionResponse.setRenderParameter(MODE_KEY, mode); 355 } else if(mode.equals(WEBLOGIC_IMPORT_MODE)) { 356 String domainDir = actionRequest.getParameter("weblogicDomainDir"); 357 String libDir = actionRequest.getParameter("weblogicLibDir"); 358 try { 359 DatabaseConversionStatus status = WebLogic81DatabaseConverter.convert(libDir, domainDir); 360 actionRequest.getPortletSession(true).setAttribute("ImportStatus", new ImportStatus(status)); 361 actionResponse.setRenderParameter(MODE_KEY, IMPORT_STATUS_MODE); 362 } catch (Exception e) { 363 log.error("Unable to import", e); 364 actionResponse.setRenderParameter("from", actionRequest.getParameter("from")); 365 actionResponse.setRenderParameter(MODE_KEY, IMPORT_START_MODE); 366 } 367 } else if(mode.equals(IMPORT_START_MODE)) { 368 actionResponse.setRenderParameter("from", actionRequest.getParameter("from")); 369 actionResponse.setRenderParameter(MODE_KEY, mode); 370 } else if(mode.equals(IMPORT_EDIT_MODE)) { 371 ImportStatus status = getImportStatus(actionRequest); 372 int index = Integer.parseInt(actionRequest.getParameter("importIndex")); 373 status.setCurrentPoolIndex(index); 374 loadImportedData(actionRequest, data, status.getCurrentPool()); 375 actionResponse.setRenderParameter(MODE_KEY, EDIT_MODE); 376 } else if(mode.equals(IMPORT_COMPLETE_MODE)) { 377 ImportStatus status = getImportStatus(actionRequest); 378 log.warn("Import Results:"); //todo: create a screen for this 379 log.warn(" "+status.getSkippedCount()+" ignored"); 380 log.warn(" "+status.getStartedCount()+" reviewed but not deployed"); 381 log.warn(" "+status.getPendingCount()+" not reviewed"); 382 log.warn(" "+status.getFinishedCount()+" deployed"); 383 actionRequest.getPortletSession().removeAttribute("ImportStatus"); 384 } else if(mode.equals(DELETE_MODE)) { 385 String name = actionRequest.getParameter("adapterAbstractName"); 386 loadConnectionFactory(actionRequest, name, data.getAbstractName(), data); 387 delete(actionRequest, actionResponse, data); 388 } else { 389 actionResponse.setRenderParameter(MODE_KEY, mode); 390 } 391 data.store(actionResponse); 392 } 393 394 private static class Downloader implements Runnable { 395 private WriteableRepository repo; 396 private DriverDownloader.DriverInfo driver; 397 private ProgressInfo progressInfo; 398 399 public Downloader(DriverDownloader.DriverInfo driver, ProgressInfo progressInfo, WriteableRepository repo) { 400 this.driver = driver; 401 this.progressInfo = progressInfo; 402 this.repo = repo; 403 } 404 405 public void run() { 406 DriverDownloader downloader = new DriverDownloader(); 407 try { 408 downloader.loadDriver(repo, driver, new FileWriteMonitor() { 409 private int fileSize; 410 411 public void writeStarted(String fileDescription, int fileSize) { 412 this.fileSize = fileSize; 413 log.info("Downloading "+fileDescription); 414 } 415 416 public void writeProgress(int bytes) { 417 int kbDownloaded = (int)Math.floor(bytes/1024); 418 if (fileSize > 0) { 419 int percent = (bytes*100)/fileSize; 420 progressInfo.setProgressPercent(percent); 421 progressInfo.setSubMessage(kbDownloaded + " / " + fileSize/1024 + " Kb downloaded"); 422 } else { 423 progressInfo.setSubMessage(kbDownloaded + " Kb downloaded"); 424 } 425 } 426 427 public void writeComplete(int bytes) { 428 log.info("Finished downloading "+bytes+" b"); 429 } 430 }); 431 } catch (IOException e) { 432 log.error("Unable to download database driver", e); 433 } finally { 434 progressInfo.setFinished(true); 435 } 436 } 437 } 438 439 private void loadImportedData(PortletRequest request, PoolData data, ImportStatus.PoolProgress progress) throws PortletException { if(!progress.getType().equals(ImportStatus.PoolProgress.TYPE_XA)) { 440 JDBCPool pool = (JDBCPool) progress.getPool(); 441 data.dbtype = "Other"; 442 data.adapterDisplayName = "TranQL Generic JDBC Resource Adapter"; 443 data.blockingTimeout = getImportString(pool.getBlockingTimeoutMillis()); 444 data.driverClass = pool.getDriverClass(); 445 data.idleTimeout = pool.getIdleTimeoutMillis() == null ? null : Integer.toString(pool.getIdleTimeoutMillis().intValue() / (60 * 1000)); 446 data.maxSize = getImportString(pool.getMaxSize()); 447 data.minSize = getImportString(pool.getMinSize()); 448 data.name = pool.getName(); 449 data.password = pool.getPassword(); 450 data.url = pool.getJdbcURL(); 451 data.user = pool.getUsername(); 452 if(pool.getDriverClass() != null) { 453 DatabaseDriver info = getDatabaseInfoFromDriver(request, data); 454 if(info != null) { 455 data.rarPath = info.getRAR().toString(); 456 data.urlPrototype = info.getURLPrototype(); 457 } else { 458 throw new PortletException("Don't recognize database driver "+data.driverClass+"!"); 459 } 460 } 461 } else { 462 //todo: handle XA 463 } 464 } 465 466 private static String getImportString(Integer value) { 467 return value == null ? null : value.toString(); 468 } 469 470 private boolean processImportUpload(ActionRequest request, ActionResponse response) throws PortletException { 471 String type = request.getParameter("importSource"); 472 response.setRenderParameter("importSource", type); 473 if (!PortletFileUpload.isMultipartContent(request)) { 474 throw new PortletException("Expected file upload"); 475 } 476 477 PortletFileUpload uploader = new PortletFileUpload(new DiskFileItemFactory()); 478 try { 479 List items = uploader.parseRequest(request); 480 for (Iterator i = items.iterator(); i.hasNext();) { 481 FileItem item = (FileItem) i.next(); 482 if (!item.isFormField()) { 483 File file = File.createTempFile("geronimo-import", ""); 484 file.deleteOnExit(); 485 log.debug("Writing database pool import file to "+file.getAbsolutePath()); 486 item.write(file); 487 DatabaseConversionStatus status = processImport(file, type); 488 request.getPortletSession(true).setAttribute("ImportStatus", new ImportStatus(status)); 489 return true; 490 } else { 491 throw new PortletException("Not expecting any form fields"); 492 } 493 } 494 } catch(PortletException e) { 495 throw e; 496 } catch(Exception e) { 497 throw new PortletException(e); 498 } 499 return false; 500 } 501 502 private DatabaseConversionStatus processImport(File importFile, String type) throws PortletException, IOException { 503 if(type.equals("JBoss 4")) { 504 return JBoss4DatabaseConverter.convert(new FileReader(importFile)); 505 } else if(type.equals("WebLogic 8.1")) { 506 return WebLogic81DatabaseConverter.convert(new FileReader(importFile)); 507 } else { 508 throw new PortletException("Unknown import type '"+type+"'"); 509 } 510 } 511 512 private ResourceAdapterParams loadConfigPropertiesByPath(PortletRequest request, String rarPath) { 513 DeploymentManager mgr = PortletManager.getDeploymentManager(request); 514 try { 515 URL url = getRAR(request, rarPath).toURL(); 516 ConnectorDeployable deployable = new ConnectorDeployable(url); 517 final DDBeanRoot ddBeanRoot = deployable.getDDBeanRoot(); 518 String adapterName = null, adapterDesc = null; 519 String[] test = ddBeanRoot.getText("connector/display-name"); 520 if(test != null && test.length > 0) { 521 adapterName = test[0]; 522 } 523 test = ddBeanRoot.getText("connector/description"); 524 if(test != null && test.length > 0) { 525 adapterDesc = test[0]; 526 } 527 DDBean[] definitions = ddBeanRoot.getChildBean("connector/resourceadapter/outbound-resourceadapter/connection-definition"); 528 List configs = new ArrayList(); 529 if(definitions != null) { 530 for (int i = 0; i < definitions.length; i++) { 531 DDBean definition = definitions[i]; 532 String iface = definition.getText("connectionfactory-interface")[0]; 533 if(iface.equals("javax.sql.DataSource")) { 534 DDBean[] beans = definition.getChildBean("config-property"); 535 for (int j = 0; j < beans.length; j++) { 536 DDBean bean = beans[j]; 537 String name = bean.getText("config-property-name")[0].trim(); 538 String type = bean.getText("config-property-type")[0].trim(); 539 test = bean.getText("config-property-value"); 540 String value = test == null || test.length == 0 ? null : test[0].trim(); 541 test = bean.getText("description"); 542 String desc = test == null || test.length == 0 ? null : test[0].trim(); 543 configs.add(new ConfigParam(name, type, desc, value)); 544 } 545 } 546 } 547 } 548 return new ResourceAdapterParams(adapterName, adapterDesc, (ConfigParam[]) configs.toArray(new ConfigParam[configs.size()])); 549 } catch (Exception e) { 550 log.error("Unable to read configuration properties", e); 551 return null; 552 } finally { 553 if(mgr != null) mgr.release(); 554 } 555 } 556 557 private ResourceAdapterParams loadConfigPropertiesByAbstractName(PortletRequest request, String abstractName) { 558 ResourceAdapterModule module = (ResourceAdapterModule) PortletManager.getManagedBean(request, new AbstractName(URI.create(abstractName))); 559 String dd = module.getDeploymentDescriptor(); 560 DocumentBuilderFactory factory = XmlUtil.newDocumentBuilderFactory(); 561 factory.setValidating(false); 562 factory.setNamespaceAware(true); 563 try { 564 DocumentBuilder builder = factory.newDocumentBuilder(); 565 final StringReader reader = new StringReader(dd); 566 Document doc = builder.parse(new InputSource(reader)); 567 reader.close(); 568 Element elem = doc.getDocumentElement(); // connector 569 String displayName = getFirstText(elem.getElementsByTagName("display-name")); 570 String description = getFirstText(elem.getElementsByTagName("description")); 571 elem = (Element) elem.getElementsByTagName("resourceadapter").item(0); 572 elem = (Element) elem.getElementsByTagName("outbound-resourceadapter").item(0); 573 NodeList defs = elem.getElementsByTagName("connection-definition"); 574 List all = new ArrayList(); 575 for(int i=0; i<defs.getLength(); i++) { 576 final Element def = (Element)defs.item(i); 577 String iface = getFirstText(def.getElementsByTagName("connectionfactory-interface")).trim(); 578 if(iface.equals("javax.sql.DataSource")) { 579 NodeList configs = def.getElementsByTagName("config-property"); 580 for(int j=0; j<configs.getLength(); j++) { 581 Element config = (Element) configs.item(j); 582 String name = getFirstText(config.getElementsByTagName("config-property-name")).trim(); 583 String type = getFirstText(config.getElementsByTagName("config-property-type")).trim(); 584 String test = getFirstText(config.getElementsByTagName("config-property-value")); 585 String value = test == null ? null : test.trim(); 586 test = getFirstText(config.getElementsByTagName("description")); 587 String desc = test == null ? null : test.trim(); 588 all.add(new ConfigParam(name, type, desc, value)); 589 } 590 } 591 } 592 return new ResourceAdapterParams(displayName, description, (ConfigParam[]) all.toArray(new ConfigParam[all.size()])); 593 } catch (Exception e) { 594 log.error("Unable to read resource adapter DD", e); 595 return null; 596 } 597 } 598 599 private String getFirstText(NodeList list) { 600 if(list.getLength() == 0) { 601 return null; 602 } 603 Element first = (Element) list.item(0); 604 StringBuffer buf = new StringBuffer(); 605 NodeList all = first.getChildNodes(); 606 for(int i=0; i<all.getLength(); i++) { 607 Node node = all.item(i); 608 if(node.getNodeType() == Node.TEXT_NODE) { 609 buf.append(node.getNodeValue()); 610 } 611 } 612 return buf.toString(); 613 } 614 615 private void loadConnectionFactory(ActionRequest actionRequest, String adapterName, String factoryName, PoolData data) { 616 AbstractName abstractAdapterName = new AbstractName(URI.create(adapterName)); 617 AbstractName abstractFactoryName = new AbstractName(URI.create(factoryName)); 618 619 ResourceAdapterModule adapter = (ResourceAdapterModule) PortletManager.getManagedBean(actionRequest,abstractAdapterName); 620 JCAManagedConnectionFactory factory = (JCAManagedConnectionFactory) PortletManager.getManagedBean(actionRequest, abstractFactoryName); 621 data.adapterDisplayName = adapter.getDisplayName(); 622 data.adapterDescription = adapter.getDescription(); 623 try { 624 data.name = (String)abstractFactoryName.getName().get("name"); 625 if(data.isGeneric()) { 626 data.url = (String) factory.getConfigProperty("ConnectionURL"); 627 data.driverClass = (String) factory.getConfigProperty("Driver"); 628 data.user = (String) factory.getConfigProperty("UserName"); 629 data.password = (String) factory.getConfigProperty("Password"); 630 } else { 631 ResourceAdapterParams params = getRARConfiguration(actionRequest, data.getRarPath(), data.getAdapterDisplayName(), adapterName); 632 for(int i=0; i<params.getConfigParams().length; i++) { 633 ConfigParam cp = params.getConfigParams()[i]; 634 Object value = factory.getConfigProperty(cp.getName()); 635 data.properties.put("property-"+cp.getName(), value == null ? null : value.toString()); 636 } 637 } 638 } catch (Exception e) { 639 log.error("Unable to look up connection property", e); 640 } 641 //todo: push the lookup into ManagementHelper 642 PoolingAttributes pool = (PoolingAttributes) factory.getConnectionManagerContainer(); 643 data.minSize = Integer.toString(pool.getPartitionMinSize()); 644 data.maxSize = Integer.toString(pool.getPartitionMaxSize()); 645 data.blockingTimeout = Integer.toString(pool.getBlockingTimeoutMilliseconds()); 646 data.idleTimeout = Integer.toString(pool.getIdleTimeoutMinutes()); 647 648 } 649 650 protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 651 if (WindowState.MINIMIZED.equals(renderRequest.getWindowState())) { 652 return; 653 } 654 try { 655 String mode = renderRequest.getParameter(MODE_KEY); 656 PoolData data = new PoolData(); 657 data.load(renderRequest); 658 renderRequest.setAttribute("pool", data); 659 // If not headed anywhere in particular, send to list 660 if(mode == null || mode.equals("")) { 661 mode = LIST_MODE; 662 } 663 // If headed to list but there's an import in progress, redirect to import status 664 if(mode.equals(LIST_MODE) && getImportStatus(renderRequest) != null) { 665 mode = IMPORT_STATUS_MODE; 666 } 667 668 if(mode.equals(LIST_MODE)) { 669 renderList(renderRequest, renderResponse); 670 } else if(mode.equals(EDIT_MODE)) { 671 renderEdit(renderRequest, renderResponse, data); 672 } else if(mode.equals(SELECT_RDBMS_MODE)) { 673 renderSelectRDBMS(renderRequest, renderResponse); 674 } else if(mode.equals(DOWNLOAD_MODE)) { 675 renderDownload(renderRequest, renderResponse); 676 } else if(mode.equals(DOWNLOAD_STATUS_MODE)) { 677 renderDownloadStatus(renderRequest, renderResponse); 678 } else if(mode.equals(BASIC_PARAMS_MODE)) { 679 renderBasicParams(renderRequest, renderResponse, data); 680 } else if(mode.equals(CONFIRM_URL_MODE)) { 681 renderConfirmURL(renderRequest, renderResponse); 682 } else if(mode.equals(TEST_CONNECTION_MODE)) { 683 renderTestConnection(renderRequest, renderResponse); 684 } else if(mode.equals(SHOW_PLAN_MODE)) { 685 renderPlan(renderRequest, renderResponse, data); 686 } else if(mode.equals(IMPORT_START_MODE)) { 687 renderImportUploadForm(renderRequest, renderResponse); 688 } else if(mode.equals(IMPORT_STATUS_MODE)) { 689 renderImportStatus(renderRequest, renderResponse); 690 } else if(mode.equals(USAGE_MODE)) { 691 renderUsage(renderRequest, renderResponse); 692 } 693 } catch (Throwable e) { 694 log.error("Unable to render portlet", e); 695 } 696 } 697 698 private void renderUsage(RenderRequest request, RenderResponse response) throws IOException, PortletException { 699 usageView.include(request, response); 700 } 701 702 private void renderImportStatus(RenderRequest request, RenderResponse response) throws IOException, PortletException { 703 request.setAttribute("status", getImportStatus(request)); 704 populatePoolList(request); 705 importStatusView.include(request, response); 706 } 707 708 private void renderImportUploadForm(RenderRequest request, RenderResponse response) throws IOException, PortletException { 709 request.setAttribute("from", request.getParameter("from")); 710 importUploadView.include(request, response); 711 } 712 713 private void renderList(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 714 populatePoolList(renderRequest); 715 listView.include(renderRequest, renderResponse); 716 } 717 718 private void populatePoolList(PortletRequest renderRequest) { 719 ResourceAdapterModule[] modules = PortletManager.getOutboundRAModules(renderRequest, "javax.sql.DataSource"); 720 List list = new ArrayList(); 721 for (int i = 0; i < modules.length; i++) { 722 ResourceAdapterModule module = modules[i]; 723 AbstractName moduleName = PortletManager.getManagementHelper(renderRequest).getNameFor(module); 724 725 JCAManagedConnectionFactory[] databases = PortletManager.getOutboundFactoriesForRA(renderRequest, module, "javax.sql.DataSource"); 726 for (int j = 0; j < databases.length; j++) { 727 JCAManagedConnectionFactory db = databases[j]; 728 AbstractName dbName = PortletManager.getManagementHelper(renderRequest).getNameFor(db); 729 list.add(new ConnectionPool(moduleName, dbName, (String)dbName.getName().get(NameFactory.J2EE_NAME), ((GeronimoManagedBean)db).getState())); 730 } 731 } 732 Collections.sort(list); 733 renderRequest.setAttribute("pools", list); 734 } 735 736 private void renderEdit(RenderRequest renderRequest, RenderResponse renderResponse, PoolData data) throws IOException, PortletException { 737 if(data.abstractName == null || data.abstractName.equals("")) { 738 loadDriverJARList(renderRequest); 739 } 740 if(!data.isGeneric()) { 741 ResourceAdapterParams params = getRARConfiguration(renderRequest, data.getRarPath(), data.getAdapterDisplayName(), renderRequest.getParameter("adapterAbstractName")); 742 data.adapterDisplayName = params.getDisplayName(); 743 data.adapterDescription = params.getDescription(); 744 Map map = new HashMap(); 745 boolean more = false; 746 for (int i = 0; i < params.getConfigParams().length; i++) { 747 ConfigParam param = params.getConfigParams()[i]; 748 if(!data.properties.containsKey("property-"+param.getName())) { 749 data.properties.put("property-"+param.getName(), param.getDefaultValue()); 750 more = true; 751 } 752 map.put("property-"+param.getName(), param); 753 } 754 if(more) { 755 data.loadPropertyNames(); 756 } 757 renderRequest.setAttribute("ConfigParams", map); 758 } 759 editView.include(renderRequest, renderResponse); 760 } 761 762 private void renderSelectRDBMS(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 763 renderRequest.setAttribute("databases", getAllDrivers(renderRequest)); 764 selectRDBMSView.include(renderRequest, renderResponse); 765 } 766 767 private void renderDownload(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 768 renderRequest.setAttribute("drivers", getDriverInfo(renderRequest)); 769 downloadView.include(renderRequest, renderResponse); 770 } 771 772 private void renderDownloadStatus(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 773 downloadStatusView.include(renderRequest, renderResponse); 774 } 775 776 private void renderBasicParams(RenderRequest renderRequest, RenderResponse renderResponse, PoolData data) throws IOException, PortletException { 777 loadDriverJARList(renderRequest); 778 // Make sure all properties available for the DB are listed 779 DatabaseDriver info = getDatabaseInfo(renderRequest, data); 780 if(info != null) { 781 String[] params = info.getURLParameters(); 782 for (int i = 0; i < params.length; i++) { 783 String param = params[i]; 784 final String key = "urlproperty-"+param; 785 if(!data.getUrlProperties().containsKey(key)) { 786 data.getUrlProperties().put(key, param.equalsIgnoreCase("port") && info.getDefaultPort() > 0 ? new Integer(info.getDefaultPort()) : null); 787 } 788 } 789 } 790 // Pass on errors 791 renderRequest.setAttribute("driverError", renderRequest.getParameter("driverError")); 792 793 basicParamsView.include(renderRequest, renderResponse); 794 } 795 796 private void loadDriverJARList(RenderRequest renderRequest) { 797 // List the available JARs 798 List list = new ArrayList(); 799 ListableRepository[] repos = PortletManager.getCurrentServer(renderRequest).getRepositories(); 800 for (int i = 0; i < repos.length; i++) { 801 ListableRepository repo = repos[i]; 802 803 SortedSet artifacts = repo.list(); 804 outer: 805 for (Iterator iterator = artifacts.iterator(); iterator.hasNext();) { 806 Artifact artifact = (Artifact) iterator.next(); 807 String test = artifact.toString(); 808 // todo should only test groupId and should check for long (org.apache.geronimo) and short form 809 for (int k = 0; k < SKIP_ENTRIES_WITH.length; k++) { 810 String skip = SKIP_ENTRIES_WITH[k]; 811 if(test.indexOf(skip) > -1) { 812 continue outer; 813 } 814 } 815 list.add(test); 816 } 817 } 818 Collections.sort(list); 819 renderRequest.setAttribute("availableJars", list); 820 } 821 822 private void renderConfirmURL(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 823 confirmURLView.include(renderRequest, renderResponse); 824 } 825 826 private void renderTestConnection(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException { 827 // Pass on results 828 renderRequest.setAttribute("connectResult", renderRequest.getParameter("connectResult")); 829 renderRequest.setAttribute("connectError", renderRequest.getPortletSession().getAttribute("connectError")); 830 testConnectionView.include(renderRequest, renderResponse); 831 } 832 833 private void renderPlan(RenderRequest renderRequest, RenderResponse renderResponse, PoolData data) throws IOException, PortletException { 834 // Pass on results 835 renderRequest.setAttribute("deploymentPlan", renderRequest.getPortletSession().getAttribute("deploymentPlan")); 836 // Digest the RAR URI 837 String path = PortletManager.getRepositoryEntry(renderRequest, data.getRarPath()).getPath(); 838 String base = PortletManager.getCurrentServer(renderRequest).getServerInfo().getCurrentBaseDirectory(); 839 if(base != null && path.startsWith(base)) { 840 path = path.substring(base.length()); 841 if(path.startsWith("/")) { 842 path = path.substring(1); 843 } 844 } else { 845 int pos = path.lastIndexOf('/'); 846 path = path.substring(pos+1); 847 } 848 renderRequest.setAttribute("rarRelativePath", path); 849 850 planView.include(renderRequest, renderResponse); 851 } 852 853 private static String attemptConnect(PortletRequest request, PoolData data) throws SQLException, IllegalAccessException, InstantiationException { 854 Class driverClass = attemptDriverLoad(request, data); 855 Driver driver = (Driver) driverClass.newInstance(); 856 if(driver.acceptsURL(data.url)) { 857 Properties props = new Properties(); 858 if(data.user != null) { 859 props.put("user", data.user); 860 } 861 if(data.password != null) { 862 props.put("password", data.password); 863 } 864 Connection con = null; 865 try { 866 con = driver.connect(data.url, props); 867 final DatabaseMetaData metaData = con.getMetaData(); 868 return metaData.getDatabaseProductName()+" "+metaData.getDatabaseProductVersion(); 869 } finally { 870 if(con != null) try{con.close();}catch(SQLException e) {} 871 } 872 } else throw new SQLException("Driver "+data.getDriverClass()+" does not accept URL "+data.url); 873 } 874 875 private void delete(PortletRequest request, ActionResponse response, PoolData data) { 876 // check to make sure the abstract name does not begin with 'org.apache.geronimo.configs' 877 // if it does not - then delete it -- otherwise it is a system database 878 if(data.getAbstractName() != null) { 879 boolean isSystemDatabasePool = (data.getAbstractName().indexOf("org.apache.geronimo.configs") == 0); 880 881 if(! isSystemDatabasePool) { 882 DeploymentManager mgr = PortletManager.getDeploymentManager(request); 883 try { 884 // retrieve all running modules 885 TargetModuleID[] runningIds = mgr.getRunningModules(ModuleType.RAR, mgr.getTargets()); 886 887 // index of module to keep 888 int index = -1; 889 890 // only keep module id that is associated with selected DB pool 891 for(int i = 0; i < runningIds.length; i++) { 892 if(data.getAbstractName().contains(runningIds[i].getModuleID())) { 893 index = i; 894 break; 895 } 896 } 897 TargetModuleID[] ids = { runningIds[index] }; 898 899 // undeploy the db pool 900 ProgressObject po = mgr.undeploy(ids); 901 waitForProgress(po); 902 903 if(po.getDeploymentStatus().isCompleted()) { 904 log.info("Undeployment completed successfully!"); 905 } 906 } catch(Exception e) { 907 log.error("Undeployment unsuccessful!"); 908 } finally { 909 if(mgr != null) mgr.release(); 910 } 911 } 912 } 913 } 914 915 private static String save(PortletRequest request, ActionResponse response, PoolData data, boolean planOnly) { 916 ImportStatus status = getImportStatus(request); 917 if(data.abstractName == null || data.abstractName.equals("")) { // we're creating a new pool 918 data.name = data.name.replaceAll("\\s", ""); 919 DeploymentManager mgr = PortletManager.getDeploymentManager(request); 920 try { 921 File rarFile = getRAR(request, data.getRarPath()); 922 ConnectorDeployable deployable = new ConnectorDeployable(rarFile.toURL()); 923 DeploymentConfiguration config = mgr.createConfiguration(deployable); 924 final DDBeanRoot ddBeanRoot = deployable.getDDBeanRoot(); 925 Connector15DCBRoot root = (Connector15DCBRoot) config.getDConfigBeanRoot(ddBeanRoot); 926 ConnectorDCB connector = (ConnectorDCB) root.getDConfigBean(ddBeanRoot.getChildBean(root.getXpaths()[0])[0]); 927 928 EnvironmentData environment = new EnvironmentData(); 929 connector.setEnvironment(environment); 930 org.apache.geronimo.deployment.service.jsr88.Artifact configId = new org.apache.geronimo.deployment.service.jsr88.Artifact(); 931 environment.setConfigId(configId); 932 configId.setGroupId("console.dbpool"); 933 String artifactId = data.name; 934 if(artifactId.indexOf('/') != -1) { 935 // slash in artifact-id results in invalid configuration-id and leads to deployment errors 936 artifactId = artifactId.replaceAll("/", "%2F"); 937 } 938 configId.setArtifactId(artifactId); 939 configId.setVersion("1.0"); 940 configId.setType("rar"); 941 942 String[] jars = data.getJars(); 943 int length = jars[jars.length - 1].length() ==0? jars.length -1: jars.length; 944 org.apache.geronimo.deployment.service.jsr88.Artifact[] dependencies = new org.apache.geronimo.deployment.service.jsr88.Artifact[length]; 945 for (int i=0; i<dependencies.length; i++) { 946 dependencies[i] = new org.apache.geronimo.deployment.service.jsr88.Artifact(); 947 } 948 environment.setDependencies(dependencies); 949 for (int i=0; i<dependencies.length; i++) { 950 Artifact tmp = Artifact.create(jars[i]); 951 dependencies[i].setGroupId(tmp.getGroupId()); 952 dependencies[i].setArtifactId(tmp.getArtifactId()); 953 dependencies[i].setVersion(tmp.getVersion().toString()); 954 dependencies[i].setType(tmp.getType()); 955 } 956 957 ResourceAdapter adapter = connector.getResourceAdapter()[0]; 958 ConnectionDefinition definition = new ConnectionDefinition(); 959 adapter.setConnectionDefinition(new ConnectionDefinition[]{definition}); 960 definition.setConnectionFactoryInterface("javax.sql.DataSource"); 961 ConnectionDefinitionInstance instance = new ConnectionDefinitionInstance(); 962 definition.setConnectionInstance(new ConnectionDefinitionInstance[]{instance}); 963 instance.setName(data.getName()); 964 ConfigPropertySetting[] settings = instance.getConfigPropertySetting(); 965 if(data.isGeneric()) { // it's a generic TranQL JDBC pool 966 for (int i = 0; i < settings.length; i++) { 967 ConfigPropertySetting setting = settings[i]; 968 if(setting.getName().equals("UserName")) { 969 setting.setValue(data.user); 970 } else if(setting.getName().equals("Password")) { 971 setting.setValue(data.password); 972 } else if(setting.getName().equals("ConnectionURL")) { 973 setting.setValue(data.url); 974 } else if(setting.getName().equals("Driver")) { 975 setting.setValue(data.driverClass); 976 } 977 } 978 } else { // it's an XA driver or non-TranQL RA 979 for (int i = 0; i < settings.length; i++) { 980 ConfigPropertySetting setting = settings[i]; 981 String value = (String) data.properties.get("property-"+setting.getName()); 982 setting.setValue(value == null ? "" : value); 983 } 984 } 985 ConnectionManager manager = instance.getConnectionManager(); 986 manager.setTransactionLocal(true); 987 SinglePool pool = new SinglePool(); 988 manager.setPoolSingle(pool); 989 pool.setMatchOne(true); 990 // Max Size needs to be set before the minimum. This is because 991 // the connection manager will constrain the minimum based on the 992 // current maximum value in the pool. We might consider adding a 993 // setPoolConstraints method to allow specifying both at the same time. 994 if(data.maxSize != null && !data.maxSize.equals("")) { 995 pool.setMaxSize(new Integer(data.maxSize)); 996 } 997 if(data.minSize != null && !data.minSize.equals("")) { 998 pool.setMinSize(new Integer(data.minSize)); 999 } 1000 if(data.blockingTimeout != null && !data.blockingTimeout.equals("")) { 1001 pool.setBlockingTimeoutMillis(new Integer(data.blockingTimeout)); 1002 } 1003 if(data.idleTimeout != null && !data.idleTimeout.equals("")) { 1004 pool.setIdleTimeoutMinutes(new Integer(data.idleTimeout)); 1005 } 1006 1007 if(planOnly) { 1008 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1009 config.save(out); 1010 out.close(); 1011 return new String(out.toByteArray(), "US-ASCII"); 1012 } else { 1013 File tempFile = File.createTempFile("console-deployment",".xml"); 1014 tempFile.deleteOnExit(); 1015 log.debug("Writing database pool deployment plan to "+tempFile.getAbsolutePath()); 1016 BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(tempFile)); 1017 config.save(out); 1018 out.flush(); 1019 out.close(); 1020 Target[] targets = mgr.getTargets(); 1021 ProgressObject po = mgr.distribute(targets, rarFile, tempFile); 1022 waitForProgress(po); 1023 if(po.getDeploymentStatus().isCompleted()) { 1024 TargetModuleID[] ids = po.getResultTargetModuleIDs(); 1025 po = mgr.start(ids); 1026 waitForProgress(po); 1027 if(po.getDeploymentStatus().isCompleted()) { 1028 ids = po.getResultTargetModuleIDs(); 1029 if(status != null) { 1030 status.getCurrentPool().setName(data.getName()); 1031 status.getCurrentPool().setConfigurationName(ids[0].getModuleID()); 1032 status.getCurrentPool().setFinished(true); 1033 response.setRenderParameter(MODE_KEY, IMPORT_STATUS_MODE); 1034 } 1035 1036 log.info("Deployment completed successfully!"); 1037 } 1038 } else if(po.getDeploymentStatus().isFailed()) { 1039 data.deployError = "Unable to deploy: " + data.name; 1040 response.setRenderParameter(MODE_KEY, EDIT_MODE); 1041 log.info("Deployment Failed!"); 1042 } 1043 } 1044 } catch (Exception e) { 1045 log.error("Unable to save connection pool", e); 1046 } finally { 1047 if(mgr != null) mgr.release(); 1048 } 1049 } else { // We're saving updates to an existing pool 1050 if(planOnly) { 1051 throw new UnsupportedOperationException("Can't update a plan for an existing deployment"); 1052 } 1053 try { 1054 JCAManagedConnectionFactory factory = (JCAManagedConnectionFactory) PortletManager.getManagedBean(request, new AbstractName(URI.create(data.getAbstractName()))); 1055 if(data.isGeneric()) { 1056 factory.setConfigProperty("ConnectionURL", data.getUrl()); 1057 factory.setConfigProperty("UserName", data.getUser()); 1058 factory.setConfigProperty("Password", data.getPassword()); 1059 } else { 1060 for (Iterator it = data.getProperties().entrySet().iterator(); it.hasNext();) { 1061 Map.Entry entry = (Map.Entry) it.next(); 1062 factory.setConfigProperty(((String) entry.getKey()).substring("property-".length()), entry.getValue()); 1063 } 1064 } 1065 //todo: push the lookup into ManagementHelper 1066 PoolingAttributes pool = (PoolingAttributes) factory.getConnectionManagerContainer(); 1067 pool.setPartitionMinSize(data.minSize == null || data.minSize.equals("") ? 0 : Integer.parseInt(data.minSize)); 1068 pool.setPartitionMaxSize(data.maxSize == null || data.maxSize.equals("") ? 10 : Integer.parseInt(data.maxSize)); 1069 pool.setBlockingTimeoutMilliseconds(data.blockingTimeout == null || data.blockingTimeout.equals("") ? 5000 : Integer.parseInt(data.blockingTimeout)); 1070 pool.setIdleTimeoutMinutes(data.idleTimeout == null || data.idleTimeout.equals("") ? 15 : Integer.parseInt(data.idleTimeout)); 1071 } catch (Exception e) { 1072 log.error("Unable to save connection pool", e); 1073 } 1074 } 1075 return null; 1076 } 1077 1078 private static void waitForProgress(ProgressObject po) { 1079 while(po.getDeploymentStatus().isRunning()) { 1080 try { 1081 Thread.sleep(100); 1082 } catch (InterruptedException e) { 1083 e.printStackTrace(); 1084 } 1085 } 1086 } 1087 1088 private static ImportStatus getImportStatus(PortletRequest request) { 1089 return (ImportStatus) request.getPortletSession(true).getAttribute("ImportStatus"); 1090 } 1091 1092 private static File getRAR(PortletRequest request, String rarPath) { 1093 org.apache.geronimo.kernel.repository.Artifact artifact = org.apache.geronimo.kernel.repository.Artifact.create(rarPath); 1094 ListableRepository[] repos = PortletManager.getCurrentServer(request).getRepositories(); 1095 for (int i = 0; i < repos.length; i++) { 1096 ListableRepository repo = repos[i]; 1097 // if the artifact is not fully resolved then try to resolve it 1098 if (!artifact.isResolved()) { 1099 SortedSet results = repo.list(artifact); 1100 if (!results.isEmpty()) { 1101 artifact = (org.apache.geronimo.kernel.repository.Artifact) results.first(); 1102 } 1103 } 1104 File url = repo.getLocation(artifact); 1105 if (url != null) { 1106 if (url.exists() && url.canRead() && !url.isDirectory()) { 1107 return url; 1108 } 1109 } 1110 } 1111 return null; 1112 } 1113 1114 /** 1115 * WARNING: This method relies on having access to the same repository 1116 * URLs as the server uses. 1117 */ 1118 private static Class attemptDriverLoad(PortletRequest request, PoolData data) { 1119 List list = new ArrayList(); 1120 try { 1121 String[] jars = data.getJars(); 1122 if(jars == null) { 1123 log.error("Driver load failed since no jar files were selected."); 1124 return null; 1125 } 1126 ListableRepository[] repos = PortletManager.getCurrentServer(request).getRepositories(); 1127 1128 for (int i = 0; i < jars.length; i++) { 1129 org.apache.geronimo.kernel.repository.Artifact artifact = org.apache.geronimo.kernel.repository.Artifact.create(jars[i]); 1130 for (int j = 0; j < repos.length; j++) { 1131 ListableRepository repo = repos[j]; 1132 File url = repo.getLocation(artifact); 1133 if (url != null) { 1134 list.add(url.toURL()); 1135 } 1136 } 1137 } 1138 URLClassLoader loader = new URLClassLoader((URL[]) list.toArray(new URL[list.size()]), DatabasePoolPortlet.class.getClassLoader()); 1139 try { 1140 return loader.loadClass(data.driverClass); 1141 } catch (ClassNotFoundException e) { 1142 return null; 1143 } 1144 } catch (Exception e) { 1145 e.printStackTrace(); 1146 return null; 1147 } 1148 } 1149 1150 private static String populateURL(String url, String[] keys, Map properties) { 1151 for (int i = 0; i < keys.length; i++) { 1152 String key = keys[i]; 1153 String value = (String) properties.get("urlproperty-"+key); 1154 if(value == null || value.equals("")) { 1155 int begin = url.indexOf("{"+key+"}"); 1156 int end = begin + key.length() + 2; 1157 for(int j=begin-1; j>=0; j--) { 1158 char c = url.charAt(j); 1159 if(c == ';' || c == ':') { 1160 begin = j; 1161 break; 1162 } else if(c == '/') { 1163 if(url.length() > end && url.charAt(end) == '/') { 1164 begin = j; // Don't leave // if foo is null for /<foo>/ 1165 } 1166 break; 1167 } 1168 } 1169 url = url.substring(0, begin)+url.substring(end); 1170 } else { 1171 if(value.indexOf('\\') != -1 || value.indexOf('$') != -1) { 1172 // value contains backslash or dollar sign and needs preprocessing for replaceAll to work properly 1173 StringBuffer temp = new StringBuffer(); 1174 char[] valueChars = value.toCharArray(); 1175 for(int j = 0; j < valueChars.length; ++j) { 1176 if(valueChars[j] == '\\' || valueChars[j] == '$') { 1177 temp.append('\\'); 1178 } 1179 temp.append(valueChars[j]); 1180 } 1181 value = temp.toString(); 1182 } 1183 url = url.replaceAll("\\{"+key+"\\}", value); 1184 } 1185 } 1186 return url; 1187 } 1188 1189 private static DatabaseDriver[] getAllDrivers(PortletRequest request) { 1190 DatabaseDriver[] result = (DatabaseDriver[]) PortletManager.getGBeansImplementing(request, DatabaseDriver.class); 1191 Arrays.sort(result, new Comparator() { 1192 public int compare(Object o1, Object o2) { 1193 String name1 = ((DatabaseDriver) o1).getName(); 1194 String name2 = ((DatabaseDriver) o2).getName(); 1195 if (name1.equals("Other")) name1 = "zzzOther"; 1196 if (name2.equals("Other")) name2 = "zzzOther"; 1197 return name1.compareTo(name2); 1198 } 1199 }); 1200 return result; 1201 } 1202 1203 private static DatabaseDriver getDatabaseInfo(PortletRequest request, PoolData data) { 1204 DatabaseDriver info = null; 1205 DatabaseDriver[] all = getAllDrivers(request); 1206 for (int i = 0; i < all.length; i++) { 1207 DatabaseDriver next = all[i]; 1208 if (next.getName().equals(data.getDbtype())) { 1209 info = next; 1210 break; 1211 } 1212 } 1213 return info; 1214 } 1215 1216 private static DatabaseDriver getDatabaseInfoFromDriver(PortletRequest request, PoolData data) { 1217 DatabaseDriver info = null; 1218 DatabaseDriver[] all = getAllDrivers(request); 1219 for (int i = 0; i < all.length; i++) { 1220 DatabaseDriver next = all[i]; 1221 if (next.getDriverClassName()!=null && next.getDriverClassName().equals(data.getDriverClass())) { 1222 info = next; 1223 break; 1224 } 1225 } 1226 return info; 1227 } 1228 1229 public static class PoolData implements Serializable { 1230 private static final long serialVersionUID = 1L; 1231 private String name; 1232 private String dbtype; 1233 private String user; 1234 private String password; 1235 private Map properties = new HashMap(); // Configuration for non-Generic drivers 1236 private Map urlProperties = new HashMap(); // URL substitution for Generic drivers 1237 private Map propertyNames; //todo: store these in the ConfigParam instead 1238 private String driverClass; 1239 private String url; 1240 private String urlPrototype; 1241 private String[] jars; 1242 private String minSize; 1243 private String maxSize; 1244 private String blockingTimeout; 1245 private String idleTimeout; 1246 private String abstractName; 1247 private String adapterDisplayName; 1248 private String adapterDescription; 1249 private String rarPath; 1250 private String importSource; 1251 private Map abstractNameMap; // generated as needed, don't need to read/write it 1252 private String deployError; 1253 1254 public void load(PortletRequest request) { 1255 name = request.getParameter("name"); 1256 if(name != null && name.equals("")) name = null; 1257 driverClass = request.getParameter("driverClass"); 1258 if(driverClass != null && driverClass.equals("")) driverClass = null; 1259 dbtype = request.getParameter("dbtype"); 1260 if(dbtype != null && dbtype.equals("")) dbtype = null; 1261 user = request.getParameter("user"); 1262 if(user != null && user.equals("")) user = null; 1263 password = request.getParameter("password"); 1264 if(password != null && password.equals("")) password = null; 1265 url = request.getParameter("url"); 1266 if(url != null && url.equals("")) { 1267 url = null; 1268 } else if(url != null && url.startsWith("URLENCODED")) { 1269 try { 1270 url = URLDecoder.decode(url.substring(10), "UTF-8"); 1271 } catch (UnsupportedEncodingException e) { 1272 throw new RuntimeException("Unable to decode URL", e); 1273 } catch(IllegalArgumentException e) { // not encoded after all?? 1274 url = url.substring(10); 1275 } 1276 } 1277 urlPrototype = request.getParameter("urlPrototype"); 1278 if(urlPrototype != null && urlPrototype.equals("")) urlPrototype = null; 1279 jars = request.getParameterValues("jars"); 1280 minSize = request.getParameter("minSize"); 1281 if(minSize != null && minSize.equals("")) minSize = null; 1282 maxSize = request.getParameter("maxSize"); 1283 if(maxSize != null && maxSize.equals("")) maxSize = null; 1284 blockingTimeout = request.getParameter("blockingTimeout"); 1285 if(blockingTimeout != null && blockingTimeout.equals("")) blockingTimeout = null; 1286 idleTimeout = request.getParameter("idleTimeout"); 1287 if(idleTimeout != null && idleTimeout.equals("")) idleTimeout = null; 1288 abstractName = request.getParameter("abstractName"); 1289 if(abstractName != null && abstractName.equals("")) abstractName = null; 1290 adapterDisplayName = request.getParameter("adapterDisplayName"); 1291 if(adapterDisplayName != null && adapterDisplayName.equals("")) adapterDisplayName = null; 1292 adapterDescription = request.getParameter("adapterDescription"); 1293 if(adapterDescription != null && adapterDescription.equals("")) adapterDescription = null; 1294 rarPath = request.getParameter("rarPath"); 1295 if(rarPath != null && rarPath.equals("")) rarPath = null; 1296 importSource = request.getParameter("importSource"); 1297 if(importSource != null && importSource.equals("")) importSource = null; 1298 Map map = request.getParameterMap(); 1299 propertyNames = new HashMap(); 1300 for (Iterator it = map.keySet().iterator(); it.hasNext();) { 1301 String key = (String) it.next(); 1302 if(key.startsWith("urlproperty-")) { 1303 urlProperties.put(key, request.getParameter(key)); 1304 } else if(key.startsWith("property-")) { 1305 properties.put(key, request.getParameter(key)); 1306 propertyNames.put(key, getPropertyName(key)); 1307 } 1308 } 1309 deployError = request.getParameter("deployError"); 1310 if(deployError != null && deployError.equals("")) deployError = null; 1311 } 1312 1313 public void loadPropertyNames() { 1314 propertyNames = new HashMap(); 1315 for (Iterator it = properties.keySet().iterator(); it.hasNext();) { 1316 String key = (String) it.next(); 1317 propertyNames.put(key, getPropertyName(key)); 1318 } 1319 } 1320 1321 private static String getPropertyName(String key) { 1322 int pos = key.indexOf('-'); 1323 key = Character.toUpperCase(key.charAt(pos+1))+key.substring(pos+2); 1324 StringBuffer buf = new StringBuffer(); 1325 pos = 0; 1326 for(int i=1; i<key.length(); i++) { 1327 if(Character.isUpperCase(key.charAt(i))) { 1328 if(Character.isUpperCase(key.charAt(i-1))) { // ongoing capitalized word 1329 1330 } else { // start of a new word 1331 buf.append(key.substring(pos, i)).append(" "); 1332 pos = i; 1333 } 1334 } else { 1335 if(Character.isUpperCase(key.charAt(i-1)) && i-pos > 1) { // first lower-case after a series of caps 1336 buf.append(key.substring(pos, i-1)).append(" "); 1337 pos = i-1; 1338 } 1339 } 1340 } 1341 buf.append(key.substring(pos)); 1342 return buf.toString(); 1343 } 1344 1345 public void store(ActionResponse response) { 1346 if(name != null) response.setRenderParameter("name", name); 1347 if(dbtype != null) response.setRenderParameter("dbtype", dbtype); 1348 if(driverClass != null) response.setRenderParameter("driverClass", driverClass); 1349 if(user != null) response.setRenderParameter("user", user); 1350 if(password != null) response.setRenderParameter("password", password); 1351 if(url != null) { // attempt to work around Pluto/Tomcat error with ; in a stored value 1352 try { 1353 response.setRenderParameter("url", "URLENCODED"+URLEncoder.encode(url, "UTF-8")); 1354 } catch (UnsupportedEncodingException e) { 1355 throw new RuntimeException("Unable to encode URL", e); 1356 } 1357 } 1358 if(urlPrototype != null) response.setRenderParameter("urlPrototype", urlPrototype); 1359 if(jars != null) response.setRenderParameter("jars", jars); 1360 if(minSize != null) response.setRenderParameter("minSize", minSize); 1361 if(maxSize != null) response.setRenderParameter("maxSize", maxSize); 1362 if(blockingTimeout != null) response.setRenderParameter("blockingTimeout", blockingTimeout); 1363 if(idleTimeout != null) response.setRenderParameter("idleTimeout", idleTimeout); 1364 if(abstractName != null) response.setRenderParameter("abstractName", abstractName); 1365 if(adapterDisplayName != null) response.setRenderParameter("adapterDisplayName", adapterDisplayName); 1366 if(adapterDescription != null) response.setRenderParameter("adapterDescription", adapterDescription); 1367 if(importSource != null) response.setRenderParameter("importSource", importSource); 1368 if(rarPath != null) response.setRenderParameter("rarPath", rarPath); 1369 for (Iterator it = urlProperties.entrySet().iterator(); it.hasNext();) { 1370 Map.Entry entry = (Map.Entry) it.next(); 1371 if(entry.getValue() != null) { 1372 response.setRenderParameter((String)entry.getKey(), (String)entry.getValue()); 1373 } 1374 } 1375 for (Iterator it = properties.entrySet().iterator(); it.hasNext();) { 1376 Map.Entry entry = (Map.Entry) it.next(); 1377 if(entry.getValue() != null) { 1378 response.setRenderParameter((String)entry.getKey(), (String)entry.getValue()); 1379 } 1380 } 1381 if(deployError != null) response.setRenderParameter("deployError", deployError); 1382 } 1383 1384 public String getName() { 1385 return name; 1386 } 1387 1388 public String getDbtype() { 1389 return dbtype; 1390 } 1391 1392 public String getUser() { 1393 return user; 1394 } 1395 1396 public String getPassword() { 1397 return password; 1398 } 1399 1400 public Map getProperties() { 1401 return properties; 1402 } 1403 1404 public Map getPropertyNames() { 1405 return propertyNames; 1406 } 1407 1408 public Map getUrlProperties() { 1409 return urlProperties; 1410 } 1411 1412 public String getUrl() { 1413 return url; 1414 } 1415 1416 public String[] getJars() { 1417 return jars; 1418 } 1419 1420 public String getMinSize() { 1421 return minSize; 1422 } 1423 1424 public String getMaxSize() { 1425 return maxSize; 1426 } 1427 1428 public String getBlockingTimeout() { 1429 return blockingTimeout; 1430 } 1431 1432 public String getIdleTimeout() { 1433 return idleTimeout; 1434 } 1435 1436 public String getDriverClass() { 1437 return driverClass; 1438 } 1439 1440 public String getUrlPrototype() { 1441 return urlPrototype; 1442 } 1443 1444 public String getAbstractName() { 1445 return abstractName; 1446 } 1447 1448 public String getAdapterDisplayName() { 1449 return adapterDisplayName; 1450 } 1451 1452 public String getAdapterDescription() { 1453 return adapterDescription; 1454 } 1455 1456 public String getRarPath() { 1457 return rarPath; 1458 } 1459 1460 public boolean isGeneric() { 1461 //todo: is there any better way to tell? 1462 return adapterDisplayName == null || adapterDisplayName.equals("TranQL Generic JDBC Resource Adapter"); 1463 } 1464 1465 public String getImportSource() { 1466 return importSource; 1467 } 1468 1469 public Map getAbstractNameMap() { 1470 if(abstractName == null) return Collections.EMPTY_MAP; 1471 if(abstractNameMap != null) return abstractNameMap; 1472 AbstractName name = new AbstractName(URI.create(abstractName)); 1473 abstractNameMap = new HashMap(name.getName()); 1474 abstractNameMap.put("domain", name.getObjectName().getDomain()); 1475 abstractNameMap.put("groupId", name.getArtifact().getGroupId()); 1476 abstractNameMap.put("artifactId", name.getArtifact().getArtifactId()); 1477 abstractNameMap.put("type", name.getArtifact().getType()); 1478 abstractNameMap.put("version", name.getArtifact().getVersion().toString()); 1479 return abstractNameMap; 1480 } 1481 1482 public String getDeployError() { 1483 return deployError; 1484 } 1485 } 1486 1487 public static class ConnectionPool implements Serializable, Comparable { 1488 private static final long serialVersionUID = 1L; 1489 private final String adapterAbstractName; 1490 private final String factoryAbstractName; 1491 private final String name; 1492 private final String parentName; 1493 private final int state; 1494 1495 public ConnectionPool(AbstractName adapterAbstractName, AbstractName factoryAbstractName, String name, int state) { 1496 this.adapterAbstractName = adapterAbstractName.toURI().toString(); 1497 String parent = (String)adapterAbstractName.getName().get(NameFactory.J2EE_APPLICATION); 1498 if(parent != null && parent.equals("null")) { 1499 parent = null; 1500 } 1501 parentName = parent; 1502 this.factoryAbstractName = factoryAbstractName.toURI().toString(); 1503 this.name = name; 1504 this.state = state; 1505 } 1506 1507 public String getAdapterAbstractName() { 1508 return adapterAbstractName; 1509 } 1510 1511 public String getFactoryAbstractName() { 1512 return factoryAbstractName; 1513 } 1514 1515 public String getName() { 1516 return name; 1517 } 1518 1519 public String getParentName() { 1520 return parentName; 1521 } 1522 1523 public int getState() { 1524 return state; 1525 } 1526 1527 public String getStateName() { 1528 return State.toString(state); 1529 } 1530 1531 public int compareTo(Object o) { 1532 final ConnectionPool pool = (ConnectionPool)o; 1533 int names = name.compareTo(pool.name); 1534 if(parentName == null) { 1535 if(pool.parentName == null) { 1536 return names; 1537 } else { 1538 return -1; 1539 } 1540 } else { 1541 if(pool.parentName == null) { 1542 return 1; 1543 } else { 1544 int test = parentName.compareTo(pool.parentName); 1545 if(test != 0) { 1546 return test; 1547 } else { 1548 return names; 1549 } 1550 } 1551 } 1552 } 1553 } 1554 1555 public static class ResourceAdapterParams { 1556 private String displayName; 1557 private String description; 1558 private ConfigParam[] configParams; 1559 1560 public ResourceAdapterParams(String displayName, String description, ConfigParam[] configParams) { 1561 this.displayName = displayName; 1562 this.description = description; 1563 this.configParams = configParams; 1564 } 1565 1566 public String getDisplayName() { 1567 return displayName; 1568 } 1569 1570 public String getDescription() { 1571 return description; 1572 } 1573 1574 public ConfigParam[] getConfigParams() { 1575 return configParams; 1576 } 1577 } 1578 1579 public static class ConfigParam { 1580 private String name; 1581 private String type; 1582 private String description; 1583 private String defaultValue; 1584 1585 public ConfigParam(String name, String type, String description, String defaultValue) { 1586 this.name = name; 1587 this.type = type; 1588 this.description = description; 1589 this.defaultValue = defaultValue; 1590 } 1591 1592 public String getName() { 1593 return name; 1594 } 1595 1596 public String getType() { 1597 return type; 1598 } 1599 1600 public String getDescription() { 1601 return description; 1602 } 1603 1604 public String getDefaultValue() { 1605 return defaultValue; 1606 } 1607 } 1608 }