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 018 package org.apache.geronimo.console.webmanager; 019 020 import java.io.IOException; 021 import java.net.URI; 022 import java.util.ArrayList; 023 import java.util.Collections; 024 import java.util.Comparator; 025 import java.util.HashMap; 026 import java.util.List; 027 028 import javax.portlet.ActionRequest; 029 import javax.portlet.ActionResponse; 030 import javax.portlet.PortletConfig; 031 import javax.portlet.PortletContext; 032 import javax.portlet.PortletException; 033 import javax.portlet.PortletRequest; 034 import javax.portlet.PortletRequestDispatcher; 035 import javax.portlet.RenderRequest; 036 import javax.portlet.RenderResponse; 037 import javax.portlet.WindowState; 038 039 import org.apache.commons.logging.Log; 040 import org.apache.commons.logging.LogFactory; 041 import org.apache.geronimo.console.BasePortlet; 042 import org.apache.geronimo.console.util.PortletManager; 043 import org.apache.geronimo.gbean.AbstractName; 044 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 045 import org.apache.geronimo.kernel.proxy.GeronimoManagedBean; 046 import org.apache.geronimo.management.geronimo.KeystoreException; 047 import org.apache.geronimo.management.geronimo.KeystoreInstance; 048 import org.apache.geronimo.management.geronimo.KeystoreManager; 049 import org.apache.geronimo.management.geronimo.NetworkConnector; 050 import org.apache.geronimo.management.geronimo.SecureConnector; 051 import org.apache.geronimo.management.geronimo.WebContainer; 052 import org.apache.geronimo.management.geronimo.WebManager; 053 import org.apache.geronimo.management.geronimo.WebManager.ConnectorAttribute; 054 import org.apache.geronimo.management.geronimo.WebManager.ConnectorType; 055 import org.apache.geronimo.crypto.KeystoreUtil; 056 057 /** 058 * A portlet that lets you list, add, remove, start, stop, restart and edit web 059 * connectors (currently, either Tomcat or Jetty). 060 * 061 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 062 */ 063 public class ConnectorPortlet extends BasePortlet { 064 private final static Log log = LogFactory.getLog(ConnectorPortlet.class); 065 066 public static final String PARM_CONTAINER_URI = "containerURI"; 067 public static final String PARM_CONNECTOR_URI = "connectorURI"; 068 public static final String PARM_MANAGER_URI = "managerURI"; 069 public static final String PARM_MODE = "mode"; 070 public static final String PARM_CONNECTOR_TYPE = "connectorType"; 071 public static final String PARM_CONNECTOR_ATTRIBUTES = "connectorAttributes"; 072 public static final String PARM_DISPLAY_NAME = "uniqueName"; 073 public static final String PARM_SERVER = "server"; 074 075 private PortletRequestDispatcher normalView; 076 private PortletRequestDispatcher maximizedView; 077 private PortletRequestDispatcher helpView; 078 private PortletRequestDispatcher editConnectorView; 079 080 public void processAction(ActionRequest actionRequest, 081 ActionResponse actionResponse) throws PortletException, IOException { 082 String submit = actionRequest.getParameter("submit"); 083 if ("Cancel".equalsIgnoreCase(submit)) { 084 // User clicked on "Cancel" button in add/edit connector page 085 actionResponse.setRenderParameter(PARM_MODE, "list"); 086 return; 087 } 088 089 String mode = actionRequest.getParameter(PARM_MODE); 090 String managerURI = actionRequest.getParameter(PARM_MANAGER_URI); 091 String containerURI = actionRequest.getParameter(PARM_CONTAINER_URI); 092 if(managerURI != null) actionResponse.setRenderParameter(PARM_MANAGER_URI, managerURI); 093 if(containerURI != null) actionResponse.setRenderParameter(PARM_CONTAINER_URI, containerURI); 094 WebContainer webContainer = null; 095 String server = null; 096 if(containerURI != null) { 097 webContainer = PortletManager.getWebContainer(actionRequest, new AbstractName(URI.create(containerURI))); 098 server = getWebServerType(webContainer.getClass()); 099 } else { 100 server = "unknown"; 101 } 102 actionResponse.setRenderParameter(PARM_SERVER, server); 103 if(mode.equals("new")) { 104 // User selected to add a new connector, need to show criteria portlet 105 actionResponse.setRenderParameter(PARM_MODE, "new"); 106 String connectorType = actionRequest.getParameter(PARM_CONNECTOR_TYPE); 107 actionResponse.setRenderParameter(PARM_CONNECTOR_TYPE, connectorType); 108 } else if(mode.equals("add")) { // User just submitted the form to add a new connector 109 // Create and configure the connector 110 WebManager manager = PortletManager.getWebManager(actionRequest, new AbstractName(URI.create(managerURI))); 111 ConnectorType connectorType = new ConnectorType(actionRequest.getParameter(PARM_CONNECTOR_TYPE)); 112 113 String uniqueName = actionRequest.getParameter(PARM_DISPLAY_NAME); 114 actionResponse.setRenderParameter(PARM_DISPLAY_NAME, uniqueName); 115 // set the connector attributes from the form post 116 List<ConnectorAttribute> connectorAttributes = manager.getConnectorAttributes(connectorType); 117 for (ConnectorAttribute attribute : connectorAttributes) { 118 String name = attribute.getAttributeName(); 119 String value = actionRequest.getParameter(name); 120 121 // handle booelan type special 122 if (attribute.getAttributeClass().equals(Boolean.class)) { 123 // browser sends value of checked checkbox as "on" or "checked" 124 if ("on".equalsIgnoreCase(value) || "checked".equalsIgnoreCase(value)) { 125 value=Boolean.toString(true); 126 } else { 127 value=Boolean.toString(false); 128 } 129 } 130 // set the string form of the attribute's value as submitted by the browser 131 if (value == null || value.trim().length()<1) { 132 // special case for KeystoreManager gbean 133 if ("trustStore".equals(attribute.getAttributeName())) { 134 attribute.setValue(null); 135 } 136 } else { 137 attribute.setStringValue(value.trim()); 138 } 139 } 140 // create the connector gbean based on the configuration data 141 AbstractName newConnectorName = manager.getConnectorConfiguration(connectorType, connectorAttributes, webContainer, uniqueName); 142 143 // set the keystore properties if its a secure connector 144 setKeystoreProperties(actionRequest, newConnectorName); 145 146 // Start the connector 147 try { 148 GeronimoManagedBean managedBean = PortletManager.getManagedBean(actionRequest, newConnectorName); 149 managedBean.startRecursive(); 150 } catch (Exception e) { 151 log.error("Unable to start connector", e); //TODO: get into rendered page 152 } 153 actionResponse.setRenderParameter(PARM_MODE, "list"); 154 } else if(mode.equals("save")) { // User just submitted the form to update a connector 155 // Get submitted values 156 //todo: lots of validation 157 String connectorURI = actionRequest.getParameter(PARM_CONNECTOR_URI); 158 // Identify and update the connector 159 AbstractName connectorName = new AbstractName(URI.create(connectorURI)); 160 NetworkConnector connector = PortletManager.getNetworkConnector(actionRequest, connectorName); 161 if(connector != null) { 162 WebManager manager = PortletManager.getWebManager(actionRequest, new AbstractName(URI.create(managerURI))); 163 ConnectorType connectorType = manager.getConnectorType(connectorName); 164 165 // set the connector attributes from the form post 166 for (ConnectorAttribute attribute : manager.getConnectorAttributes(connectorType)) { 167 String name = attribute.getAttributeName(); 168 String value = actionRequest.getParameter(name); 169 170 // handle booelan type special 171 if (attribute.getAttributeClass().equals(Boolean.class)) { 172 // browser sends value of checked checkbox as "on" or "checked" 173 if ("on".equalsIgnoreCase(value) || "checked".equalsIgnoreCase(value)) { 174 value=Boolean.toString(true); 175 } else { 176 value=Boolean.toString(false); 177 } 178 } 179 // set the string form of the attribute's value as submitted by the browser 180 if (value == null || value.trim().length()<1) { 181 // special case for KeystoreManager gbean 182 if ("trustStore".equals(attribute.getAttributeName())) { 183 setProperty(connector,name,null); 184 } 185 } else { 186 // set the string value on the ConnectorAttribute so 187 // it can handle type conversion via getValue() 188 try { 189 attribute.setStringValue(value); 190 setProperty(connector,name,attribute.getValue()); 191 } catch (Exception e) { 192 log.error("Unable to set property " + attribute.getAttributeName(), e); 193 } 194 } 195 } 196 197 // set the keystore properties if its a secure connector 198 setKeystoreProperties(actionRequest, connectorName); 199 } 200 actionResponse.setRenderParameter(PARM_MODE, "list"); 201 } else if(mode.equals("start")) { 202 String connectorURI = actionRequest.getParameter(PARM_CONNECTOR_URI); 203 // work with the current connector to start it. 204 NetworkConnector connector = PortletManager.getNetworkConnector(actionRequest, new AbstractName(URI.create(connectorURI))); 205 if(connector != null) { 206 try { 207 ((GeronimoManagedBean)connector).startRecursive(); 208 } catch (Exception e) { 209 log.error("Unable to start connector", e); //todo: get into rendered page somehow? 210 } 211 } 212 else { 213 log.error("Incorrect connector reference"); //Replace this with correct error processing 214 } 215 actionResponse.setRenderParameter(PARM_CONNECTOR_URI, connectorURI); 216 actionResponse.setRenderParameter(PARM_MODE, "list"); 217 } else if(mode.equals("stop")) { 218 String connectorURI = actionRequest.getParameter(PARM_CONNECTOR_URI); 219 // work with the current connector to stop it. 220 NetworkConnector connector = PortletManager.getNetworkConnector(actionRequest, new AbstractName(URI.create(connectorURI))); 221 if(connector != null) { 222 try { 223 ((GeronimoManagedBean)connector).stop(); 224 } catch (Exception e) { 225 log.error("Unable to stop connector", e); //todo: get into rendered page somehow? 226 } 227 } 228 else { 229 log.error("Incorrect connector reference"); //Replace this with correct error processing 230 } 231 actionResponse.setRenderParameter(PARM_CONNECTOR_URI, connectorURI); 232 actionResponse.setRenderParameter(PARM_MODE, "list"); 233 } else if(mode.equals("restart")) { 234 String connectorURI = actionRequest.getParameter(PARM_CONNECTOR_URI); 235 // work with the current connector to restart it. 236 NetworkConnector connector = PortletManager.getNetworkConnector(actionRequest, new AbstractName(URI.create(connectorURI))); 237 if(connector != null) { 238 try { 239 ((GeronimoManagedBean)connector).stop(); 240 ((GeronimoManagedBean)connector).start(); 241 } catch (Exception e) { 242 log.error("Unable to restart connector", e); //todo: get into rendered page somehow? 243 } 244 } else { 245 log.error("Incorrect connector reference"); //Replace this with correct error processing 246 } 247 actionResponse.setRenderParameter(PARM_CONNECTOR_URI, connectorURI); 248 actionResponse.setRenderParameter(PARM_MODE, "list"); 249 } else if(mode.equals("edit")) { 250 String connectorURI = actionRequest.getParameter(PARM_CONNECTOR_URI); 251 actionResponse.setRenderParameter(PARM_CONNECTOR_URI, connectorURI); 252 actionResponse.setRenderParameter(PARM_MODE, "edit"); 253 254 } else if(mode.equals("delete")) { // User chose to delete a connector 255 String connectorURI = actionRequest.getParameter(PARM_CONNECTOR_URI); 256 PortletManager.getWebManager(actionRequest, new AbstractName(URI.create(managerURI))).removeConnector(new AbstractName(URI.create(connectorURI))); 257 actionResponse.setRenderParameter(PARM_MODE, "list"); 258 } 259 } 260 261 protected void doView(RenderRequest renderRequest, 262 RenderResponse renderResponse) throws IOException, PortletException { 263 if (WindowState.MINIMIZED.equals(renderRequest.getWindowState())) { 264 return; 265 } 266 String mode = renderRequest.getParameter(PARM_MODE); 267 if(mode == null || mode.equals("")) { 268 mode = "list"; 269 } 270 271 if(mode.equals("list")) { 272 doList(renderRequest, renderResponse); 273 } else { 274 String managerURI = renderRequest.getParameter(PARM_MANAGER_URI); 275 String containerURI = renderRequest.getParameter(PARM_CONTAINER_URI); 276 if(managerURI != null) renderRequest.setAttribute(PARM_MANAGER_URI, managerURI); 277 if(containerURI != null) renderRequest.setAttribute(PARM_CONTAINER_URI, containerURI); 278 279 WebContainer container = PortletManager.getWebContainer(renderRequest, new AbstractName(URI.create(containerURI))); 280 String server = getWebServerType(container.getClass()); 281 renderRequest.setAttribute(PARM_SERVER, server); 282 283 if(mode.equals("new")) { 284 String connectorType = renderRequest.getParameter(PARM_CONNECTOR_TYPE); 285 WebManager webManager = PortletManager.getWebManager(renderRequest, new AbstractName(URI.create(managerURI))); 286 ConnectorType type = new ConnectorType(connectorType); 287 List<ConnectorAttribute> connectorAttributes = webManager.getConnectorAttributes(type); 288 sortConnectorAttributes(connectorAttributes); 289 renderRequest.setAttribute(PARM_CONNECTOR_ATTRIBUTES, connectorAttributes); 290 renderRequest.setAttribute(PARM_CONNECTOR_TYPE, connectorType); 291 renderRequest.setAttribute(PARM_MODE, "add"); 292 populateEnumAttributes(renderRequest); 293 editConnectorView.include(renderRequest, renderResponse); 294 } else if(mode.equals("edit")) { 295 String connectorURI = renderRequest.getParameter(PARM_CONNECTOR_URI); 296 NetworkConnector connector = PortletManager.getNetworkConnector(renderRequest, new AbstractName(URI.create(connectorURI))); 297 if(connector == null) { 298 doList(renderRequest, renderResponse); 299 } else { 300 AbstractName connectorName = new AbstractName(URI.create(connectorURI)); 301 String uniqueName = connectorName.getName().get("name").toString(); 302 renderRequest.setAttribute(PARM_DISPLAY_NAME, uniqueName); 303 WebManager webManager = PortletManager.getWebManager(renderRequest, new AbstractName(URI.create(managerURI))); 304 ConnectorType connectorType = webManager.getConnectorType(connectorName); 305 List<ConnectorAttribute> connectorAttributes = webManager.getConnectorAttributes(connectorType); 306 sortConnectorAttributes(connectorAttributes); 307 308 // populate the connector attributes from the connector 309 for (ConnectorAttribute attribute : connectorAttributes) { 310 try { 311 Object value = getProperty(connector, attribute.getAttributeName()); 312 attribute.setValue(value); 313 } catch (IllegalArgumentException e) { 314 log.error("Unable to retrieve value of property " + attribute.getAttributeName(), e); 315 } 316 } 317 318 renderRequest.setAttribute(PARM_CONNECTOR_ATTRIBUTES, connectorAttributes); 319 renderRequest.setAttribute(PARM_CONNECTOR_URI, connectorURI); 320 // populate any enum type values. the browser will render them in a 321 // <SELECT> input for the attribute 322 populateEnumAttributes(renderRequest); 323 324 renderRequest.setAttribute(PARM_MODE, "save"); 325 editConnectorView.include(renderRequest, renderResponse); 326 } 327 } 328 } 329 330 } 331 332 // sorts connector attributes alphabetically, required attributes listed first 333 private void sortConnectorAttributes(List<ConnectorAttribute> connectorAttributes) { 334 Collections.sort(connectorAttributes, new Comparator<ConnectorAttribute>() { 335 public int compare(ConnectorAttribute o1, ConnectorAttribute o2) { 336 if (o1.isRequired()) { 337 if (o2.isRequired()) { 338 return o1.getAttributeName().compareTo(o2.getAttributeName()); 339 } 340 return -1; 341 } 342 if (o2.isRequired()) { 343 return 1; 344 } 345 return o1.getAttributeName().compareTo(o2.getAttributeName()); 346 } 347 }); 348 } 349 350 private void doList(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException { 351 WebManager[] managers = PortletManager.getWebManagers(renderRequest); 352 List<ContainerInfo> all = new ArrayList<ContainerInfo>(); 353 for (int i = 0; i < managers.length; i++) { 354 WebManager manager = managers[i]; 355 AbstractName webManagerName = PortletManager.getNameFor(renderRequest, manager); 356 357 WebContainer[] containers = (WebContainer[]) manager.getContainers(); 358 for (int j = 0; j < containers.length; j++) { 359 List<ConnectorInfo> beans = new ArrayList<ConnectorInfo>(); 360 WebContainer container = containers[j]; 361 AbstractName containerName = PortletManager.getNameFor(renderRequest, container); 362 String id; 363 if(containers.length == 1) { 364 id = manager.getProductName(); 365 } else { 366 id = manager.getProductName() + " (" + containerName.getName().get(NameFactory.J2EE_NAME) + ")"; 367 } 368 ContainerInfo result = new ContainerInfo(id, webManagerName.toString(), containerName.toString()); 369 370 for (NetworkConnector connector : manager.getConnectorsForContainer(container)) { 371 ConnectorInfo info = new ConnectorInfo(); 372 AbstractName connectorName = PortletManager.getNameFor(renderRequest, connector); 373 info.setConnectorURI(connectorName.toString()); 374 info.setDescription(PortletManager.getGBeanDescription(renderRequest, connectorName)); 375 info.setUniqueName((String)connectorName.getName().get(NameFactory.J2EE_NAME)); 376 info.setState(((GeronimoManagedBean)connector).getState()); 377 info.setPort(connector.getPort()); 378 try { 379 info.setProtocol(connector.getProtocol()); 380 } catch (IllegalStateException e) { 381 info.setProtocol("unknown"); 382 } 383 beans.add(info); 384 } 385 result.setConnectors(beans); 386 result.setConnectorTypes(manager.getConnectorTypes()); 387 all.add(result); 388 } 389 } 390 renderRequest.setAttribute("containers", all); 391 renderRequest.setAttribute("serverPort", new Integer(renderRequest.getServerPort())); 392 393 if (WindowState.NORMAL.equals(renderRequest.getWindowState())) { 394 normalView.include(renderRequest, renderResponse); 395 } else { 396 maximizedView.include(renderRequest, renderResponse); 397 } 398 } 399 400 public final static class ContainerInfo { 401 private String name; 402 private String managerURI; 403 private String containerURI; 404 private List connectorTypes; 405 private List connectors; 406 407 public ContainerInfo(String name, String managerURI, String containerURI) { 408 this.name = name; 409 this.managerURI = managerURI; 410 this.containerURI = containerURI; 411 } 412 413 public String getName() { 414 return name; 415 } 416 417 public List getConnectorTypes() { 418 return connectorTypes; 419 } 420 421 public void setConnectorTypes(List connectorTypes) { 422 this.connectorTypes = connectorTypes; 423 } 424 425 public List getConnectors() { 426 return connectors; 427 } 428 429 public void setConnectors(List connectors) { 430 this.connectors = connectors; 431 } 432 433 public String getManagerURI() { 434 return managerURI; 435 } 436 437 public String getContainerURI() { 438 return containerURI; 439 } 440 } 441 442 protected void doHelp(RenderRequest renderRequest, 443 RenderResponse renderResponse) throws PortletException, IOException { 444 helpView.include(renderRequest, renderResponse); 445 } 446 447 public void init(PortletConfig portletConfig) throws PortletException { 448 super.init(portletConfig); 449 PortletContext pc = portletConfig.getPortletContext(); 450 normalView = pc.getRequestDispatcher("/WEB-INF/view/webmanager/connector/normal.jsp"); 451 maximizedView = pc.getRequestDispatcher("/WEB-INF/view/webmanager/connector/maximized.jsp"); 452 helpView = pc.getRequestDispatcher("/WEB-INF/view/webmanager/connector/help.jsp"); 453 editConnectorView = pc.getRequestDispatcher("/WEB-INF/view/webmanager/connector/editConnector.jsp"); 454 } 455 456 public void destroy() { 457 normalView = null; 458 maximizedView = null; 459 helpView = null; 460 editConnectorView = null; 461 super.destroy(); 462 } 463 464 public static boolean isValid(String s) { 465 return s != null && !s.equals(""); 466 } 467 468 // stash any 'enum' type values for attributes. right now this is 469 // hardcoded, need to promote these to the ConnectorAttribute apis 470 private void populateEnumAttributes(PortletRequest request) { 471 HashMap<String,String[]> enumValues = new HashMap<String,String[]>(); 472 473 // provide the two possible values for secure protocol - TLS and SSL 474 enumValues.put("secureProtocol", new String[] { "TLS", "SSL" }); //jetty 475 enumValues.put("sslProtocol", new String[] { "TLS", "SSL" }); //tomcat 476 477 // keystore and truststore types for tomcat 478 enumValues.put("keystoreType", KeystoreUtil.keystoreTypes.toArray(new String[0])); 479 enumValues.put("truststoreType", KeystoreUtil.keystoreTypes.toArray(new String[0])); 480 481 // provide the three possible values for secure algorithm - Default, SunX509, and IbmX509 482 enumValues.put("algorithm", new String[] { "Default", "SunX509", "IbmX509" }); 483 484 // provide the possible values for the keystore name 485 KeystoreManager mgr = PortletManager.getCurrentServer(request).getKeystoreManager(); 486 KeystoreInstance[] stores = mgr.getUnlockedKeyStores(); 487 String[] storeNames = new String[stores.length]; 488 for (int i = 0; i < storeNames.length; i++) { 489 storeNames[i] = stores[i].getKeystoreName(); 490 } 491 enumValues.put("keyStore", storeNames); 492 493 // provide the possible values for the trust store name 494 KeystoreInstance[] trusts = mgr.getUnlockedTrustStores(); 495 String[] trustNames = new String[trusts.length]; 496 for (int i = 0; i < trustNames.length; i++) { 497 trustNames[i] = trusts[i].getKeystoreName(); 498 } 499 enumValues.put("trustStore", trustNames); 500 501 request.setAttribute("geronimoConsoleEnumValues", enumValues); 502 } 503 504 // get the special keystore properties from the request and set them on the connector 505 // TODO: need a more generic way to handle this 506 private void setKeystoreProperties(PortletRequest request, AbstractName connectorName) throws PortletException { 507 String containerURI = request.getParameter(PARM_CONTAINER_URI); 508 WebContainer container = PortletManager.getWebContainer(request, new AbstractName(URI.create(containerURI))); 509 String server = getWebServerType(container.getClass()); 510 NetworkConnector connector = PortletManager.getNetworkConnector(request, connectorName); 511 512 // return if not a secure connector 513 if (!(connector instanceof SecureConnector)) { 514 return; 515 } 516 517 // right now only jetty supports the KeystoreManager 518 if (server.equals(WEB_SERVER_JETTY)) { 519 String keyStore = request.getParameter("keyStore"); 520 521 // get the unlocked keystore object from the keystore managaer 522 // gbean and set its keyalias directly on the connector 523 try { 524 KeystoreInstance[] keystores = PortletManager.getCurrentServer(request) 525 .getKeystoreManager().getKeystores(); 526 527 String[] keys = null; 528 for (int i = 0; i < keystores.length; i++) { 529 KeystoreInstance keystore = keystores[i]; 530 if (keystore.getKeystoreName().equals(keyStore)) { 531 keys = keystore.getUnlockedKeys(null); 532 } 533 } 534 if (keys != null && keys.length == 1) { 535 setProperty(connector, "keyAlias", keys[0]); 536 } else { 537 throw new PortletException("Cannot handle keystores with anything but 1 unlocked private key"); 538 } 539 } catch (KeystoreException e) { 540 throw new PortletException(e); 541 } 542 } 543 } 544 }