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    package org.apache.servicemix.console;
018    
019    import org.apache.commons.logging.Log;
020    import org.apache.commons.logging.LogFactory;
021    import org.apache.servicemix.jbi.audit.AuditorMBean;
022    import org.apache.servicemix.jbi.audit.jdbc.JdbcAuditor;
023    import org.apache.servicemix.jbi.container.JBIContainer;
024    import org.apache.servicemix.jbi.framework.DeploymentService;
025    import org.apache.servicemix.jbi.framework.InstallationService;
026    import org.apache.servicemix.jbi.management.ManagementContext;
027    import org.apache.servicemix.jbi.management.ManagementContextMBean;
028    
029    import javax.jbi.management.DeploymentServiceMBean;
030    import javax.jbi.management.InstallationServiceMBean;
031    import javax.jbi.management.LifeCycleMBean;
032    import javax.management.MBeanServerConnection;
033    import javax.management.MBeanServerInvocationHandler;
034    import javax.management.ObjectName;
035    import javax.management.remote.JMXConnector;
036    import javax.management.remote.JMXConnectorFactory;
037    import javax.management.remote.JMXServiceURL;
038    import javax.portlet.ActionRequest;
039    import javax.portlet.ActionResponse;
040    import javax.portlet.GenericPortlet;
041    import javax.portlet.PortletConfig;
042    import javax.portlet.PortletContext;
043    import javax.portlet.PortletException;
044    import javax.portlet.PortletRequestDispatcher;
045    import javax.portlet.RenderRequest;
046    import javax.portlet.RenderResponse;
047    import javax.portlet.WindowState;
048    import javax.servlet.ServletContext;
049    
050    import java.io.IOException;
051    import java.net.MalformedURLException;
052    import java.util.HashMap;
053    import java.util.Map;
054    
055    public abstract class ServiceMixPortlet extends GenericPortlet {
056    
057        protected final Log log = LogFactory.getLog(getClass());
058        
059        protected PortletRequestDispatcher normalView;
060        protected PortletRequestDispatcher helpView;
061        protected PortletRequestDispatcher errorView;
062    
063        private JMXConnector jmxConnector;
064        private String namingHost = "localhost";
065        private String containerName = JBIContainer.DEFAULT_NAME;
066        private String jmxDomainName = ManagementContext.DEFAULT_DOMAIN;
067        private String jmxUrl;
068        private int namingPort = ManagementContext.DEFAULT_CONNECTOR_PORT;
069        private String jndiPath = ManagementContext.DEFAULT_CONNECTOR_PATH;
070        private String username;
071        private String password;
072    
073        /**
074         * Get the JMXServiceURL - built from the protocol used and host names
075         * @return the url
076         */
077        public JMXServiceURL getServiceURL() {
078            JMXServiceURL url = null;
079            if (url == null) {
080                try {
081                    String jmxUrl = this.jmxUrl;
082                    if (jmxUrl == null) {
083                        jmxUrl = "service:jmx:rmi:///jndi/rmi://" + namingHost + ":" + namingPort + jndiPath;
084                    }
085                    url = new JMXServiceURL(jmxUrl);
086                }
087                catch (MalformedURLException e) {
088                    log.error("error creating serviceURL: ", e);
089                }
090            }
091            return url;
092        }
093        
094        /**
095         * Get a JMXConnector from a url
096         * @param url
097         * @return the JMXConnector
098         * @throws IOException
099         */
100        public JMXConnector getJMXConnector (JMXServiceURL url) throws IOException {
101            log.info("Connecting to JBI Container at: " + url);
102            String[] credentials = new String[] { username, password };
103            Map environment = new HashMap();
104            environment.put(JMXConnector.CREDENTIALS, credentials);
105            return JMXConnectorFactory.connect(url, environment);
106        }
107        
108        protected void doHelp(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException {
109            log.debug("doHelp");
110            helpView.include(renderRequest, renderResponse);
111        }
112    
113        protected void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException, IOException {
114            log.debug("doView");
115            if (WindowState.MINIMIZED.equals(renderRequest.getWindowState())) {
116                return;
117            }
118            try {
119                // Retrieve the jmx connector
120                if (this.jmxConnector == null) {
121                    this.jmxConnector = getJMXConnector(getServiceURL());
122                }
123                renderView(renderRequest, renderResponse);
124            } catch (PortletException e) {
125                log.error("Error rendering portlet", e);
126                closeConnector();
127                throw e;
128            } catch (IOException e) {
129                log.error("Error rendering portlet", e);
130                closeConnector();
131                throw e;
132            } catch (Exception e) {
133                try {
134                    log.debug("Error rendering portlet", e);
135                    renderRequest.setAttribute("exception", e);
136                    errorView.include(renderRequest, renderResponse);
137                } finally {
138                    closeConnector();
139                }
140                //log.error("Error rendering portlet", e);
141                //throw new PortletException("Error rendering portlet", e);
142            }
143        }
144        
145        protected void renderView(RenderRequest renderRequest, RenderResponse renderResponse) throws Exception {
146            // Fill request
147            fillViewRequest(renderRequest);
148            // Render view
149            normalView.include(renderRequest, renderResponse);
150        }
151        
152        /**
153         * Get a servicemix internal system management instance, from it's class name
154         * @param systemClass
155         * @return the object name
156         */
157        protected  ObjectName getObjectName (Class systemClass){
158            return ManagementContext.getSystemObjectName(jmxDomainName, getContainerName(), systemClass);
159        }
160        
161        
162        protected void fillViewRequest(RenderRequest request) throws Exception {
163        }
164    
165        public void init(PortletConfig portletConfig) throws PortletException {
166            log.debug("init");
167            super.init(portletConfig);
168            PortletContext pc = portletConfig.getPortletContext();
169            normalView = pc.getRequestDispatcher("/WEB-INF/view/" + getPortletName() + "/view.jsp");
170            helpView = pc.getRequestDispatcher("/WEB-INF/view/" + getPortletName() + "/help.jsp");
171            errorView = pc.getRequestDispatcher("/WEB-INF/view/error.jsp");
172    
173            jmxUrl = getConfigString("servicemixJmxUrl", jmxUrl);
174            username = getConfigString("servicemixJmxUsername", username);
175            password = getConfigString("servicemixJmxPassword", password);
176            containerName = getConfigString("servicemixContainerName", containerName);
177        }
178        
179        protected String getConfigString(String name, String defValue) {
180            ServletContext ctx = ContextLoaderListener.getServletContext();
181            if (ctx != null) {
182                String v = ctx.getInitParameter(name);
183                if (v != null) {
184                    return v;
185                }
186            }
187            return defValue;
188        }
189    
190        public void processAction(ActionRequest actionRequest, ActionResponse actionResponse) throws PortletException, IOException {
191            log.debug("processAction: " + actionRequest);
192            try {
193                // Retrieve the jmx connector
194                if (this.jmxConnector == null) {
195                    this.jmxConnector = getJMXConnector(getServiceURL());
196                }
197                // Fill request
198                doProcessAction(actionRequest, actionResponse);
199            } catch (PortletException e) {
200                log.error("Error processing action", e);
201                closeConnector();
202                throw e;
203            } catch (IOException e) {
204                log.error("Error processing action", e);
205                closeConnector();
206                throw e;
207            } catch (Exception e) {
208                log.error("Error processing action", e);
209                closeConnector();
210                throw new PortletException("Error processing action", e);
211            }
212        }
213    
214        protected void doProcessAction(ActionRequest actionRequest, ActionResponse actionResponse) throws Exception {
215        }
216    
217        public void destroy() {
218            closeConnector();
219            super.destroy();
220        }
221        
222        protected void closeConnector() {
223            if (this.jmxConnector != null){
224                try {
225                    jmxConnector.close();
226                } catch (Exception e) {
227                    log.warn("caught an error closing the jmxConnector", e);
228                } finally {
229                    jmxConnector = null;
230                }
231            }
232        }
233        
234        /**
235         * Get the InstallationServiceMBean
236         * @return the installation service MBean
237         * @throws IOException
238         */
239        public InstallationServiceMBean getInstallationService() throws IOException {
240            ObjectName objectName = getObjectName(InstallationService.class);
241            return (InstallationServiceMBean) getProxy(objectName, InstallationServiceMBean.class);
242        }
243        
244        /**
245         * Get the DeploymentServiceMBean 
246         * @return the deployment service mbean
247         * @throws IOException
248         */
249        public DeploymentServiceMBean getDeploymentService() throws IOException {
250            ObjectName objectName = getObjectName(DeploymentService.class);
251            return (DeploymentServiceMBean) getProxy(objectName, DeploymentServiceMBean.class);
252        }
253        
254        
255        /**
256         * Get the ManagementContextMBean 
257         * @return the management service mbean
258         * @throws IOException
259         */
260        public ManagementContextMBean getManagementContext() throws IOException {
261            ObjectName objectName = getObjectName(ManagementContext.class);
262            return (ManagementContextMBean) getProxy(objectName, ManagementContextMBean.class);
263        }
264        
265        public AuditorMBean getJdbcAuditor() throws IOException {
266            ObjectName objectName = getObjectName(JdbcAuditor.class);
267            return (AuditorMBean) getProxy(objectName, AuditorMBean.class);
268        }
269        
270        public LifeCycleMBean getJBIContainer() throws IOException {
271            ObjectName objectName = ManagementContext.getContainerObjectName(jmxDomainName, containerName);
272            return (LifeCycleMBean) getProxy(objectName, LifeCycleMBean.class);
273        }
274        
275        public Object getProxy(ObjectName name, Class type) throws IOException {
276            return MBeanServerInvocationHandler.newProxyInstance(getServerConnection(), name, type, true);
277        }
278        
279        public MBeanServerConnection getServerConnection() throws IOException {
280            return jmxConnector.getMBeanServerConnection();
281        }
282    
283        public String getContainerName() {
284            return containerName;
285        }
286    
287        public void setContainerName(String containerName) {
288            this.containerName = containerName;
289        }
290        
291        /**
292         * @return the password
293         */
294        protected String getPassword() {
295            return password;
296        }
297    
298        /**
299         * @param password the password to set
300         */
301        protected void setPassword(String password) {
302            this.password = password;
303        }
304    
305        /**
306         * @return the username
307         */
308        protected String getUsername() {
309            return username;
310        }
311    
312        /**
313         * @param username the username to set
314         */
315        protected void setUsername(String username) {
316            this.username = username;
317        }
318    
319    }