1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.geronimo.console.configmanager;
19
20 import java.io.IOException;
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import javax.portlet.ActionRequest;
31 import javax.portlet.ActionResponse;
32 import javax.portlet.PortletConfig;
33 import javax.portlet.PortletException;
34 import javax.portlet.PortletRequestDispatcher;
35 import javax.portlet.RenderRequest;
36 import javax.portlet.RenderResponse;
37 import javax.portlet.WindowState;
38
39 import org.apache.geronimo.console.BasePortlet;
40 import org.apache.geronimo.console.util.PortletManager;
41 import org.apache.geronimo.gbean.AbstractName;
42 import org.apache.geronimo.gbean.AbstractNameQuery;
43 import org.apache.geronimo.gbean.GBeanData;
44 import org.apache.geronimo.kernel.DependencyManager;
45 import org.apache.geronimo.kernel.InternalKernelException;
46 import org.apache.geronimo.kernel.Kernel;
47 import org.apache.geronimo.kernel.KernelRegistry;
48 import org.apache.geronimo.kernel.config.Configuration;
49 import org.apache.geronimo.kernel.config.ConfigurationInfo;
50 import org.apache.geronimo.kernel.config.ConfigurationManager;
51 import org.apache.geronimo.kernel.config.ConfigurationModuleType;
52 import org.apache.geronimo.kernel.config.ConfigurationUtil;
53 import org.apache.geronimo.kernel.config.InvalidConfigException;
54 import org.apache.geronimo.kernel.config.LifecycleException;
55 import org.apache.geronimo.kernel.config.LifecycleResults;
56 import org.apache.geronimo.kernel.config.NoSuchConfigException;
57 import org.apache.geronimo.kernel.management.State;
58 import org.apache.geronimo.kernel.repository.Artifact;
59 import org.apache.geronimo.kernel.repository.MissingDependencyException;
60 import org.apache.geronimo.management.geronimo.WebModule;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class ConfigManagerPortlet extends BasePortlet {
65
66 private static final Logger logger = LoggerFactory.getLogger(ConfigManagerPortlet.class);
67
68 private static final String START_ACTION = "start";
69
70 private static final String STOP_ACTION = "stop";
71
72 private static final String RESTART_ACTION = "restart";
73
74 private static final String UNINSTALL_ACTION = "uninstall";
75
76 private static final String CONFIG_INIT_PARAM = "config-type";
77
78 private static final String SHOW_DEPENDENCIES_COOKIE = "org.apache.geronimo.configmanager.showDependencies";
79
80 private Kernel kernel;
81
82 private PortletRequestDispatcher normalView;
83
84 private PortletRequestDispatcher maximizedView;
85
86 private PortletRequestDispatcher helpView;
87
88 private boolean showDisplayName;
89
90 private String moduleType;
91
92 private static List<String> loadChildren(Kernel kernel, String configName) {
93 List<String> kids = new ArrayList<String>();
94
95 Map<String, String> filter = new HashMap<String, String>();
96 filter.put("J2EEApplication", configName);
97 filter.put("j2eeType", "WebModule");
98
99 Set<AbstractName> test = kernel.listGBeans(new AbstractNameQuery(null, filter));
100 for (AbstractName child : test) {
101 String childName = child.getNameProperty("name");
102 kids.add(childName);
103 }
104
105 filter.put("j2eeType", "EJBModule");
106 test = kernel.listGBeans(new AbstractNameQuery(null, filter));
107 for (AbstractName child : test) {
108 String childName = child.getNameProperty("name");
109 kids.add(childName);
110 }
111
112 filter.put("j2eeType", "AppClientModule");
113 test = kernel.listGBeans(new AbstractNameQuery(null, filter));
114 for (AbstractName child : test) {
115 String childName = child.getNameProperty("name");
116 kids.add(childName);
117 }
118
119 filter.put("j2eeType", "ResourceAdapterModule");
120 test = kernel.listGBeans(new AbstractNameQuery(null, filter));
121 for (AbstractName child : test) {
122 String childName = child.getNameProperty("name");
123 kids.add(childName);
124 }
125 return kids;
126 }
127
128 public String printResults(Set<Artifact> lcresult) {
129 StringBuilder sb = new StringBuilder();
130 for (Artifact config : lcresult) {
131
132 // TODO might be a hack
133 List<String> kidsChild = loadChildren(kernel, config.toString());
134
135 // TODO figure out the web url and show it when appropriate.
136 sb.append("<br />").append(config);
137 for (String kid : kidsChild) {
138 sb.append("<br />-> ").append(kid);
139 }
140 }
141 return sb.toString();
142 }
143
144 public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException {
145 String action = actionRequest.getParameter("action");
146 actionResponse.setRenderParameter("message", ""); // set to blank first
147 try {
148 ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
149 String config = getConfigID(actionRequest);
150 Artifact configId = Artifact.create(config);
151
152 if (START_ACTION.equals(action)) {
153 if(!configurationManager.isLoaded(configId)) {
154 configurationManager.loadConfiguration(configId);
155 }
156 if(!configurationManager.isRunning(configId)) {
157 org.apache.geronimo.kernel.config.LifecycleResults lcresult = configurationManager.startConfiguration(configId);
158 addInfoMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.infoMsg01") + printResults(lcresult.getStarted()));
159 }
160 } else if (STOP_ACTION.equals(action)) {
161 if(configurationManager.isLoaded(configId)) {
162 LifecycleResults lcresult = configurationManager.unloadConfiguration(configId);
163 addInfoMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.infoMsg02") + printResults(lcresult.getStopped()));
164 }
165 } else if (UNINSTALL_ACTION.equals(action)) {
166 configurationManager.uninstallConfiguration(configId);
167 addInfoMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.infoMsg04") + "<br />" + configId);
168 } else if (RESTART_ACTION.equals(action)) {
169 LifecycleResults lcresult = configurationManager.restartConfiguration(configId);
170 addInfoMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.infoMsg03") + printResults(lcresult.getStarted()));
171 } else {
172 addWarningMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.warnMsg01") + action + "<br />");
173 throw new PortletException("Invalid value for changeState: " + action);
174 }
175 } catch (NoSuchConfigException e) {
176 // ignore this for now
177 addErrorMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.errorMsg01"));
178 logger.error("Configuration not found", e);
179 } catch (LifecycleException e) {
180 // todo we have a much more detailed report now
181 addErrorMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.errorMsg02"));
182 logger.error("Lifecycle operation failed ", e);
183 } catch (Throwable e) {
184 addErrorMessage(actionRequest, getLocalizedString(actionRequest, "consolebase.errorMsg03"));
185 logger.error("Exception", e);
186 }
187 }
188
189 /**
190 * Check if a configuration should be listed here. This method depends on the "config-type" portlet parameter
191 * which is set in portle.xml.
192 */
193 private boolean shouldListConfig(ConfigurationModuleType info) {
194 String configType = getInitParameter(CONFIG_INIT_PARAM);
195 return configType == null || info.getName().equalsIgnoreCase(configType);
196 }
197
198 private String getConfigID(ActionRequest actionRequest) {
199 return actionRequest.getParameter("configId");
200 }
201
202 protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
203 if (WindowState.MINIMIZED.equals(renderRequest.getWindowState())) {
204 return;
205 }
206
207 String cookies = renderRequest.getProperty("cookie");
208 boolean showDependencies = (cookies != null && cookies.indexOf(SHOW_DEPENDENCIES_COOKIE + "=true") > 0);
209
210 List<ModuleDetails> moduleDetails = new ArrayList<ModuleDetails>();
211 ConfigurationManager configManager = ConfigurationUtil.getConfigurationManager(kernel);
212 List<ConfigurationInfo> infos = configManager.listConfigurations();
213 for (ConfigurationInfo info : infos) {
214 if (ConfigurationModuleType.WAR.getName().equalsIgnoreCase(moduleType)) {
215
216 if (info.getType().getValue() == ConfigurationModuleType.WAR.getValue()) {
217 ModuleDetails details = new ModuleDetails(info.getConfigID(), info.getType(), info.getState());
218 try {
219 AbstractName configObjName = Configuration.getConfigurationAbstractName(info.getConfigID());
220 boolean loaded = loadModule(configManager, configObjName);
221
222 WebModule webModule = (WebModule) PortletManager.getModule(renderRequest, info.getConfigID());
223
224 if (webModule != null) {
225 details.getContextPaths().add(webModule.getContextPath());
226 details.setDisplayName(webModule.getDisplayName());
227 }
228
229 if (showDependencies) {
230 addDependencies(details, configObjName);
231 }
232
233 if (loaded) {
234 unloadModule(configManager, configObjName);
235 }
236 } catch (InvalidConfigException ice) {
237 // Should not occur
238 ice.printStackTrace();
239 }
240 moduleDetails.add(details);
241 } else if (info.getType().getValue() == ConfigurationModuleType.EAR.getValue()) {
242 try {
243 AbstractName configObjName = Configuration.getConfigurationAbstractName(info.getConfigID());
244 boolean loaded = loadModule(configManager, configObjName);
245
246 Configuration config = configManager.getConfiguration(info.getConfigID());
247 if(config != null){
248 for (Configuration child : config.getChildren()) {
249 if (child.getModuleType().getValue() == ConfigurationModuleType.WAR.getValue()) {
250 ModuleDetails childDetails = new ModuleDetails(info.getConfigID(), child.getModuleType(), info.getState());
251 childDetails.setComponentName(child.getId().toString());
252 WebModule webModule = getWebModule(config, child);
253 if (webModule != null) {
254 childDetails.getContextPaths().add(webModule.getContextPath());
255 childDetails.setDisplayName(webModule.getDisplayName());
256 }
257 if (showDependencies) {
258 addDependencies(childDetails, configObjName);
259 }
260 moduleDetails.add(childDetails);
261 }
262 }
263 }
264
265 if (loaded) {
266 unloadModule(configManager, configObjName);
267 }
268 } catch (InvalidConfigException ice) {
269 // Should not occur
270 ice.printStackTrace();
271 }
272 }
273
274 } else if (shouldListConfig(info.getType())) {
275 ModuleDetails details = new ModuleDetails(info.getConfigID(), info.getType(), getConfigurationState(info));
276 try {
277 AbstractName configObjName = Configuration.getConfigurationAbstractName(info.getConfigID());
278 boolean loaded = loadModule(configManager, configObjName);
279
280 if (info.getType().getValue() == ConfigurationModuleType.EAR.getValue()) {
281 Configuration config = configManager.getConfiguration(info.getConfigID());
282 if(config != null){
283 Iterator childs = config.getChildren().iterator();
284 while (childs.hasNext()) {
285 Configuration child = (Configuration) childs.next();
286 if (child.getModuleType().getValue() == ConfigurationModuleType.WAR.getValue()) {
287 WebModule webModule = getWebModule(config, child);
288 if (webModule != null) {
289 details.getContextPaths().add(webModule.getContextPath());
290 }
291 }
292 }
293 }
294 } else if (info.getType().equals(ConfigurationModuleType.CAR)) {
295 Configuration config = configManager.getConfiguration(info.getConfigID());
296 details.setClientAppServerSide(config.getOwnedConfigurations().size() > 0);
297 }
298 if (showDependencies) {
299 addDependencies(details, configObjName);
300 }
301 if (loaded) {
302 unloadModule(configManager, configObjName);
303 }
304 } catch (InvalidConfigException ice) {
305 // Should not occur
306 ice.printStackTrace();
307 }
308 moduleDetails.add(details);
309 }
310 }
311 Collections.sort(moduleDetails);
312 renderRequest.setAttribute("configurations", moduleDetails);
313 renderRequest.setAttribute("showWebInfo", Boolean.valueOf(showWebInfo()));
314 renderRequest.setAttribute("showDisplayName", Boolean.valueOf(showDisplayName));
315 renderRequest.setAttribute("showDependencies", Boolean.valueOf(showDependencies));
316 if (moduleDetails.size() == 0) {
317 addWarningMessage(renderRequest, getLocalizedString(renderRequest, "consolebase.warnMsg02"));
318 }
319 if (WindowState.NORMAL.equals(renderRequest.getWindowState())) {
320 normalView.include(renderRequest, renderResponse);
321 } else {
322 maximizedView.include(renderRequest, renderResponse);
323 }
324 }
325
326 private State getConfigurationState(ConfigurationInfo configurationInfo) {
327 State configurationState = configurationInfo.getState();
328 if (configurationState.isRunning()) {
329 // Check whether the Configuration's sub-gbeans are running
330 try {
331 Configuration configuration = PortletManager.getConfigurationManager().getConfiguration(configurationInfo.getConfigID());
332 Map<AbstractName, GBeanData> abstractNameGBeanDataMap = configuration.getGBeans();
333 // Check one sub-GBean's state, if one gbean fails to start, all will be shutdown
334 Iterator<AbstractName> it = abstractNameGBeanDataMap.keySet().iterator();
335 if (it.hasNext()) {
336 AbstractName abstractName = it.next();
337 if (!PortletManager.getKernel().isRunning(abstractName)) {
338 return State.STOPPED;
339 }
340 }
341 } catch (InternalKernelException e) {
342 return State.STOPPED;
343 } catch (IllegalStateException e) {
344 return State.STOPPED;
345 }
346 }
347 return configurationState;
348 }
349
350 private WebModule getWebModule(Configuration config, Configuration child) {
351 try {
352 Map<String, String> query1 = new HashMap<String, String>();
353 String name = config.getId().getArtifactId();
354 query1.put("J2EEApplication", config.getId().toString());
355 query1.put("j2eeType", "WebModule");
356 query1.put("name", child.getId().getArtifactId().substring(name.length()+1));
357 AbstractName childName = new AbstractName(config.getAbstractName().getArtifact(), query1);
358 return (WebModule)kernel.getGBean(childName);
359 } catch(Exception h){
360 // No gbean found, will not happen
361 // Except if module not started, ignored
362 }
363 return null;
364 }
365
366 private boolean loadModule(ConfigurationManager configManager, AbstractName configObjName) {
367 if(!kernel.isLoaded(configObjName)) {
368 try {
369 configManager.loadConfiguration(configObjName.getArtifact());
370 return true;
371 } catch (NoSuchConfigException e) {
372 // Should not occur
373 e.printStackTrace();
374 } catch (LifecycleException e) {
375 // config could not load because one or more of its dependencies
376 // has been removed. cannot load the configuration in this case,
377 // so don't rely on that technique to discover its parents or children
378 if (e.getCause() instanceof MissingDependencyException) {
379 // do nothing
380 } else {
381 e.printStackTrace();
382 }
383 }
384 }
385 return false;
386 }
387
388 private void addDependencies(ModuleDetails details, AbstractName configObjName) {
389 DependencyManager depMgr = kernel.getDependencyManager();
390 Set<AbstractName> parents = depMgr.getParents(configObjName);
391 for (AbstractName parent : parents) {
392 details.getParents().add(parent.getArtifact());
393 }
394 Set<AbstractName> children = depMgr.getChildren(configObjName);
395 for (AbstractName child : children) {
396 //if(configManager.isConfiguration(child.getArtifact()))
397 if (child.getNameProperty("configurationName") != null) {
398 details.getChildren().add(child.getArtifact());
399 }
400 }
401 Collections.sort(details.getParents());
402 Collections.sort(details.getChildren());
403 }
404
405 private void unloadModule(ConfigurationManager configManager, AbstractName configObjName) {
406 try {
407 configManager.unloadConfiguration(configObjName.getArtifact());
408 } catch (NoSuchConfigException e) {
409 // Should not occur
410 e.printStackTrace();
411 }
412 }
413
414 private boolean showWebInfo() {
415 return ConfigurationModuleType.WAR.getName().equalsIgnoreCase(moduleType) ||
416 ConfigurationModuleType.EAR.getName().equalsIgnoreCase(moduleType);
417 }
418
419 protected void doHelp(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException {
420 helpView.include(renderRequest, renderResponse);
421 }
422
423 public void init(PortletConfig portletConfig) throws PortletException {
424 super.init(portletConfig);
425 kernel = KernelRegistry.getSingleKernel();
426 normalView = portletConfig.getPortletContext().getRequestDispatcher("/WEB-INF/view/configmanager/normal.jsp");
427 maximizedView = portletConfig.getPortletContext().getRequestDispatcher("/WEB-INF/view/configmanager/maximized.jsp");
428 helpView = portletConfig.getPortletContext().getRequestDispatcher("/WEB-INF/view/configmanager/help.jsp");
429 moduleType = getInitParameter(CONFIG_INIT_PARAM);
430 //Only show the displayNames for the web applications
431 showDisplayName = ConfigurationModuleType.WAR.getName().equalsIgnoreCase(moduleType);
432 }
433
434 public void destroy() {
435 normalView = null;
436 maximizedView = null;
437 kernel = null;
438 super.destroy();
439 }
440
441 /**
442 * Convenience data holder for portlet that displays deployed modules.
443 * Includes context path information for web modules.
444 */
445 public static class ModuleDetails implements Comparable, Serializable {
446 private static final long serialVersionUID = -7022687152297202079L;
447 private final Artifact configId;
448 private final ConfigurationModuleType type;
449 private final State state;
450 private List<Artifact> parents = new ArrayList<Artifact>();
451 private List<Artifact> children = new ArrayList<Artifact>();
452 private boolean expertConfig = false; // used to mark this config as one that should only be managed (stop/uninstall) by expert users.
453 private List<String> contextPaths = new ArrayList<String>();
454 private String componentName;
455 //This flag is used to indicate whether it is the client side if the module is a client application
456 private boolean clientAppServerSide = false;
457 private String displayName;
458
459 public ModuleDetails(Artifact configId, ConfigurationModuleType type, State state) {
460 this.configId = configId;
461 this.type = type;
462 this.state = state;
463 if (configId.toString().indexOf("org.apache.geronimo.configs/") == 0) {
464 this.expertConfig = true;
465 }
466 }
467
468 public int compareTo(Object o) {
469 if (o != null && o instanceof ModuleDetails){
470 return configId.compareTo(((ModuleDetails)o).configId);
471 } else {
472 return -1;
473 }
474 }
475
476 public Artifact getConfigId() {
477 return configId;
478 }
479
480 public State getState() {
481 return state;
482 }
483
484 public ConfigurationModuleType getType() {
485 return type;
486 }
487
488 public boolean getExpertConfig() {
489 return expertConfig;
490 }
491
492 public List<Artifact> getParents() {
493 return parents;
494 }
495
496 public List<Artifact> getChildren() {
497 return children;
498 }
499
500 public List<String> getContextPaths() {
501 return contextPaths;
502 }
503
504 public String getComponentName(){
505 return componentName;
506 }
507
508 public void setComponentName(String name){
509 componentName = name;
510 }
511
512 public String getDisplayName(){
513 return displayName;
514 }
515
516 public void setDisplayName(String name){
517 displayName = name;
518 }
519
520 public void setClientAppServerSide(boolean clientAppServerSide) {
521 this.clientAppServerSide = clientAppServerSide;
522 }
523
524 public boolean isClientAppServerSide() {
525 return this.clientAppServerSide;
526 }
527 }
528 }