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