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 }