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