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    }