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.configmanager;
019    
020    import java.io.IOException;
021    import java.io.Serializable;
022    import java.util.ArrayList;
023    import java.util.Collections;
024    import java.util.HashMap;
025    import java.util.Iterator;
026    import java.util.List;
027    import java.util.Map;
028    import java.util.Set;
029    
030    import javax.portlet.ActionRequest;
031    import javax.portlet.ActionResponse;
032    import javax.portlet.PortletConfig;
033    import javax.portlet.PortletException;
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.geronimo.console.BasePortlet;
040    import org.apache.geronimo.console.util.PortletManager;
041    import org.apache.geronimo.gbean.AbstractName;
042    import org.apache.geronimo.gbean.AbstractNameQuery;
043    import org.apache.geronimo.kernel.DependencyManager;
044    import org.apache.geronimo.kernel.Kernel;
045    import org.apache.geronimo.kernel.KernelRegistry;
046    import org.apache.geronimo.kernel.config.Configuration;
047    import org.apache.geronimo.kernel.config.ConfigurationInfo;
048    import org.apache.geronimo.kernel.config.ConfigurationManager;
049    import org.apache.geronimo.kernel.config.ConfigurationModuleType;
050    import org.apache.geronimo.kernel.config.ConfigurationUtil;
051    import org.apache.geronimo.kernel.config.InvalidConfigException;
052    import org.apache.geronimo.kernel.config.LifecycleException;
053    import org.apache.geronimo.kernel.config.LifecycleResults;
054    import org.apache.geronimo.kernel.config.NoSuchConfigException;
055    import org.apache.geronimo.kernel.management.State;
056    import org.apache.geronimo.kernel.repository.Artifact;
057    import org.apache.geronimo.kernel.repository.MissingDependencyException;
058    import org.apache.geronimo.management.geronimo.WebModule;
059    import org.apache.commons.logging.Log;
060    import org.apache.commons.logging.LogFactory;
061    
062    /**
063     * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
064     */
065    public class ConfigManagerPortlet extends BasePortlet {
066        private final static Log log = LogFactory.getLog(ConfigManagerPortlet.class);
067        
068        private static final String START_ACTION = "start";
069    
070        private static final String STOP_ACTION = "stop";
071    
072        private static final String RESTART_ACTION = "restart";
073    
074        private static final String UNINSTALL_ACTION = "uninstall";
075    
076        private static final String CONFIG_INIT_PARAM = "config-type";
077    
078        private static final String SHOW_DEPENDENCIES_COOKIE = "org.apache.geronimo.configmanager.showDependencies";
079        
080        private Kernel kernel;
081    
082        private PortletRequestDispatcher normalView;
083    
084        private PortletRequestDispatcher maximizedView;
085    
086        private PortletRequestDispatcher helpView;
087    
088        private static List loadChildren(Kernel kernel, String configName) {
089            List<String> kids = new ArrayList<String>();
090    
091            Map<String, String> filter = new HashMap<String, String>();
092            filter.put("J2EEApplication", configName);
093            filter.put("j2eeType", "WebModule");
094    
095            Set<AbstractName> test = kernel.listGBeans(new AbstractNameQuery(null, filter));
096            for (AbstractName child : test) {
097                String childName = child.getNameProperty("name");
098                kids.add(childName);
099            }
100    
101            filter.put("j2eeType", "EJBModule");
102            test = kernel.listGBeans(new AbstractNameQuery(null, filter));
103            for (AbstractName child : test) {
104                String childName = child.getNameProperty("name");
105                kids.add(childName);
106            }
107    
108            filter.put("j2eeType", "AppClientModule");
109            test = kernel.listGBeans(new AbstractNameQuery(null, filter));
110            for (AbstractName child : test) {
111                String childName = child.getNameProperty("name");
112                kids.add(childName);
113            }
114    
115            filter.put("j2eeType", "ResourceAdapterModule");
116            test = kernel.listGBeans(new AbstractNameQuery(null, filter));
117            for (AbstractName child : test) {
118                String childName = child.getNameProperty("name");
119                kids.add(childName);
120            }
121            return kids;
122        }
123    
124        public void printResults(Set<Artifact> lcresult, StringBuffer buf) {
125            for (Artifact config : lcresult) {
126    
127                //TODO might be a hack
128                List<String> kidsChild = loadChildren(kernel, config.toString());
129    
130                //TODO figure out the web url and show it when appropriate.
131                buf.append("    ").append(config).append("<br />");
132                for (String kid: kidsChild) {
133                    buf.append("      `-> ").append(kid).append("<br />");
134                }
135                buf.append("<br />");
136            }
137        }
138    
139        public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException {
140            String action = actionRequest.getParameter("action");
141            actionResponse.setRenderParameter("message", ""); // set to blank first
142            try {
143                ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
144                String config = getConfigID(actionRequest);
145                Artifact configId = Artifact.create(config);
146    
147                if (START_ACTION.equals(action)) {
148                    if(!configurationManager.isLoaded(configId)) {
149                        configurationManager.loadConfiguration(configId);
150                    }
151                    if(!configurationManager.isRunning(configId)) {
152                        org.apache.geronimo.kernel.config.LifecycleResults lcresult = configurationManager.startConfiguration(configId);
153                        message(actionResponse, lcresult, "Started application<br /><br />");
154                    }
155                } else if (STOP_ACTION.equals(action)) {
156                    if(configurationManager.isRunning(configId)) {
157                        configurationManager.stopConfiguration(configId);
158                    }
159                    if(configurationManager.isLoaded(configId)) {
160                        LifecycleResults lcresult = configurationManager.unloadConfiguration(configId);
161                        message(actionResponse, lcresult, "Stopped application<br /><br />");
162                    }
163                } else if (UNINSTALL_ACTION.equals(action)) {
164                    configurationManager.uninstallConfiguration(configId);
165                    message(actionResponse, null, "Uninstalled application<br /><br />"+configId+"<br /><br />");
166                } else if (RESTART_ACTION.equals(action)) {
167                    LifecycleResults lcresult = configurationManager.restartConfiguration(configId);
168                    message(actionResponse, lcresult, "Restarted application<br /><br />");
169                } else {
170                    message(actionResponse, null, "Invalid value for changeState: " + action + "<br /><br />");
171                    throw new PortletException("Invalid value for changeState: " + action);
172                }
173            } catch (NoSuchConfigException e) {
174                // ignore this for now
175                message(actionResponse, null, "Configuration not found<br /><br />");
176                log.error("Configuration not found", e);
177            } catch (LifecycleException e) {
178                // todo we have a much more detailed report now
179                message(actionResponse, null, "Lifecycle operation failed<br /><br />");
180                log.error("Lifecycle operation failed ", e);
181            } catch (Exception e) {
182                message(actionResponse, null, "Encountered an unhandled exception<br /><br />");
183                log.error("Exception", e);
184            }
185        }
186    
187        private void message(ActionResponse actionResponse, LifecycleResults lcresult, String str) {
188            StringBuffer buf = new StringBuffer(str);
189            if (lcresult != null) {
190                this.printResults(lcresult.getStarted(), buf);
191            }
192            actionResponse.setRenderParameter("messageStatus", buf.toString());
193        }
194    
195        /**
196         * Check if a configuration should be listed here. This method depends on the "config-type" portlet parameter
197         * which is set in portle.xml.
198         */
199        private boolean shouldListConfig(ConfigurationModuleType info) {
200            String configType = getInitParameter(CONFIG_INIT_PARAM);
201            return configType == null || info.getName().equalsIgnoreCase(configType);
202        }
203    
204        private String getConfigID(ActionRequest actionRequest) {
205            return actionRequest.getParameter("configId");
206        }
207    
208        protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
209            if (WindowState.MINIMIZED.equals(renderRequest.getWindowState())) {
210                return;
211            }
212                  
213            String cookies = renderRequest.getProperty("cookie");
214            boolean showDependencies = (cookies != null && cookies.indexOf(SHOW_DEPENDENCIES_COOKIE + "=true") > 0);
215            
216            List<ModuleDetails> moduleDetails = new ArrayList<ModuleDetails>();
217            ConfigurationManager configManager = ConfigurationUtil.getConfigurationManager(kernel);
218            List<ConfigurationInfo> infos = configManager.listConfigurations();
219            for (ConfigurationInfo info : infos) {
220    
221                String moduleType = getInitParameter(CONFIG_INIT_PARAM);
222                if (ConfigurationModuleType.WAR.getName().equalsIgnoreCase(moduleType)) {
223    
224                    if (info.getType().getValue() == ConfigurationModuleType.WAR.getValue()) {
225                        ModuleDetails details = new ModuleDetails(info.getConfigID(), info.getType(), info.getState());
226                        try {
227                            AbstractName configObjName = Configuration.getConfigurationAbstractName(info.getConfigID());
228                            boolean loaded = loadModule(configManager, configObjName);
229    
230                            WebModule webModule = (WebModule) PortletManager.getModule(renderRequest, info.getConfigID());
231                            if (webModule != null) {
232                                details.getContextPaths().add(webModule.getContextPath());
233                            }
234    
235                            if (showDependencies) {
236                                addDependencies(details, configObjName);
237                            }
238                            if (loaded) {
239                                unloadModule(configManager, configObjName);
240                            }
241                        } catch (InvalidConfigException ice) {
242                            // Should not occur
243                            ice.printStackTrace();
244                        }
245                        moduleDetails.add(details);
246                    } else if (info.getType().getValue() == ConfigurationModuleType.EAR.getValue()) {
247                        try {
248                            AbstractName configObjName = Configuration.getConfigurationAbstractName(info.getConfigID());
249                            boolean loaded = loadModule(configManager, configObjName);
250    
251                            Configuration config = configManager.getConfiguration(info.getConfigID());
252                            if(config != null){
253                                for (Configuration child : config.getChildren()) {
254                                    if (child.getModuleType().getValue() == ConfigurationModuleType.WAR.getValue()) {
255                                        ModuleDetails childDetails = new ModuleDetails(info.getConfigID(), child.getModuleType(), info.getState());
256                                        childDetails.setComponentName(child.getId().toString());
257                                        WebModule webModule = getWebModule(config, child);
258                                        if (webModule != null) {
259                                            childDetails.getContextPaths().add(webModule.getContextPath());
260                                        }
261                                        if (showDependencies) {
262                                            addDependencies(childDetails, configObjName);
263                                        }
264                                        moduleDetails.add(childDetails);
265                                    }
266                                }
267                            }
268    
269                            if (loaded) {
270                                unloadModule(configManager, configObjName);
271                            }
272                        } catch (InvalidConfigException ice) {
273                            // Should not occur
274                            ice.printStackTrace();
275                        }
276                    }
277    
278                } else if (shouldListConfig(info.getType())) {
279                    ModuleDetails details = new ModuleDetails(info.getConfigID(), info.getType(), info.getState());
280                    try {
281                        AbstractName configObjName = Configuration.getConfigurationAbstractName(info.getConfigID());
282                        boolean loaded = loadModule(configManager, configObjName);
283    
284                        if (info.getType().getValue() == ConfigurationModuleType.EAR.getValue()) {
285                            Configuration config = configManager.getConfiguration(info.getConfigID());
286                            if(config != null){
287                                Iterator childs = config.getChildren().iterator();
288                                while (childs.hasNext()) {
289                                    Configuration child = (Configuration) childs.next();
290                                    if (child.getModuleType().getValue() == ConfigurationModuleType.WAR.getValue()) {
291                                        WebModule webModule = getWebModule(config, child);
292                                        if (webModule != null) {
293                                            details.getContextPaths().add(webModule.getContextPath());
294                                        }
295                                    }
296                                }                                            
297                                if (showDependencies) {
298                                    addDependencies(details, configObjName);
299                                }
300                            }
301                        }
302                        if (loaded) {
303                            unloadModule(configManager, configObjName);
304                        }
305                    } catch (InvalidConfigException ice) {
306                        // Should not occur
307                        ice.printStackTrace();
308                    }
309                    moduleDetails.add(details);
310                }
311            }
312            Collections.sort(moduleDetails);
313            renderRequest.setAttribute("configurations", moduleDetails);
314            renderRequest.setAttribute("showWebInfo", Boolean.valueOf(showWebInfo()));
315            renderRequest.setAttribute("showDependencies", Boolean.valueOf(showDependencies));
316            if (moduleDetails.size() == 0) {
317                renderRequest.setAttribute("messageInstalled", "No modules found of this type<br /><br />");
318            } else {
319                renderRequest.setAttribute("messageInstalled", "");
320            }
321            renderRequest.setAttribute("messageStatus", renderRequest.getParameter("messageStatus"));
322            if (WindowState.NORMAL.equals(renderRequest.getWindowState())) {
323                normalView.include(renderRequest, renderResponse);
324            } else {
325                maximizedView.include(renderRequest, renderResponse);
326            }
327        }
328    
329        private WebModule getWebModule(Configuration config, Configuration child) {
330            try {
331                Map<String, String> query1 = new HashMap<String, String>();
332                String name = config.getId().getArtifactId();
333                query1.put("J2EEApplication", config.getId().toString());
334                query1.put("j2eeType", "WebModule");
335                query1.put("name", child.getId().getArtifactId().substring(name.length()+1));
336                AbstractName childName = new AbstractName(config.getAbstractName().getArtifact(), query1);
337                return (WebModule)kernel.getGBean(childName);
338            } catch(Exception h){
339                // No gbean found, will not happen 
340                // Except if module not started, ignored
341            }
342            return null;
343        }
344        
345        private boolean loadModule(ConfigurationManager configManager, AbstractName configObjName) {
346            if(!kernel.isLoaded(configObjName)) {
347                try {
348                    configManager.loadConfiguration(configObjName.getArtifact());
349                    return true;
350                } catch (NoSuchConfigException e) {
351                    // Should not occur
352                    e.printStackTrace();
353                } catch (LifecycleException e) {
354                    // config could not load because one or more of its dependencies
355                    // has been removed. cannot load the configuration in this case,
356                    // so don't rely on that technique to discover its parents or children
357                    if (e.getCause() instanceof MissingDependencyException) {
358                        // do nothing
359                    } else {
360                        e.printStackTrace();
361                    }
362                }
363            }
364            return false;
365        }
366        
367        private void addDependencies(ModuleDetails details, AbstractName configObjName) {
368            DependencyManager depMgr = kernel.getDependencyManager();
369            Set<AbstractName> parents = depMgr.getParents(configObjName);
370            for (AbstractName parent : parents) {
371                details.getParents().add(parent.getArtifact());
372            }
373            Set<AbstractName> children = depMgr.getChildren(configObjName);
374            for (AbstractName child : children) {
375                //if(configManager.isConfiguration(child.getArtifact()))
376                if (child.getNameProperty("configurationName") != null) {
377                    details.getChildren().add(child.getArtifact());
378                }
379            }
380            Collections.sort(details.getParents());
381            Collections.sort(details.getChildren());
382        }
383        
384        private void unloadModule(ConfigurationManager configManager, AbstractName configObjName) {
385            try {
386                configManager.unloadConfiguration(configObjName.getArtifact());
387            } catch (NoSuchConfigException e) {
388                // Should not occur
389                e.printStackTrace();
390            }        
391        }
392        
393        private boolean showWebInfo() {
394            String moduleType = getInitParameter(CONFIG_INIT_PARAM);
395            return ConfigurationModuleType.WAR.getName().equalsIgnoreCase(moduleType) ||
396                   ConfigurationModuleType.EAR.getName().equalsIgnoreCase(moduleType);
397        }
398        
399        protected void doHelp(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException {
400            helpView.include(renderRequest, renderResponse);
401        }
402    
403        public void init(PortletConfig portletConfig) throws PortletException {
404            super.init(portletConfig);
405            kernel = KernelRegistry.getSingleKernel();
406            normalView = portletConfig.getPortletContext().getRequestDispatcher("/WEB-INF/view/configmanager/normal.jsp");
407            maximizedView = portletConfig.getPortletContext().getRequestDispatcher("/WEB-INF/view/configmanager/maximized.jsp");
408            helpView = portletConfig.getPortletContext().getRequestDispatcher("/WEB-INF/view/configmanager/help.jsp");
409        }
410    
411        public void destroy() {
412            normalView = null;
413            maximizedView = null;
414            kernel = null;
415            super.destroy();
416        }
417    
418        /**
419         * Convenience data holder for portlet that displays deployed modules.
420         * Includes context path information for web modules.
421         */
422        public static class ModuleDetails implements Comparable, Serializable {
423            private static final long serialVersionUID = -7022687152297202079L;
424            private final Artifact configId;
425            private final ConfigurationModuleType type;
426            private final State state;
427            private List<Artifact> parents = new ArrayList<Artifact>();
428            private List<Artifact> children = new ArrayList<Artifact>();
429            private boolean expertConfig = false;   // used to mark this config as one that should only be managed (stop/uninstall) by expert users.
430            private List<String> contextPaths = new ArrayList<String>();
431            private String componentName;
432    
433            public ModuleDetails(Artifact configId, ConfigurationModuleType type, State state) {
434                this.configId = configId;
435                this.type = type;
436                this.state = state;
437                if (configId.toString().indexOf("org.apache.geronimo.configs/") == 0) {
438                    this.expertConfig = true;
439                }
440            }
441    
442            public int compareTo(Object o) {
443                if (o != null && o instanceof ModuleDetails){
444                    return configId.compareTo(((ModuleDetails)o).configId);
445                } else {
446                    return -1;
447                }
448            }
449    
450            public Artifact getConfigId() {
451                return configId;
452            }
453    
454            public State getState() {
455                return state;
456            }
457    
458            public ConfigurationModuleType getType() {
459                return type;
460            }
461    
462            public boolean getExpertConfig() {
463                return expertConfig;
464            }
465    
466            public List<Artifact> getParents() {
467                return parents;
468            }
469    
470            public List<Artifact> getChildren() {
471                return children;
472            }
473            
474            public List<String> getContextPaths() {
475                return contextPaths;
476            }     
477            
478            public String getComponentName(){
479                return componentName;
480            }
481            
482            public void setComponentName(String name){
483                componentName = name;
484            }
485        }
486    }