001    /* 
002        Licensed to the Apache Software Foundation (ASF) under one
003        or more contributor license agreements.  See the NOTICE file
004        distributed with this work for additional information
005        regarding copyright ownership.  The ASF licenses this file
006        to you under the Apache License, Version 2.0 (the
007        "License"); you may not use this file except in compliance
008        with the License.  You may obtain a copy of the License at
009    
010           http://www.apache.org/licenses/LICENSE-2.0
011    
012        Unless required by applicable law or agreed to in writing,
013        software distributed under the License is distributed on an
014        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015        KIND, either express or implied.  See the License for the
016        specific language governing permissions and limitations
017        under the License.  
018     */
019    package org.apache.wiki.ui.admin;
020    
021    import java.lang.management.ManagementFactory;
022    import java.util.ArrayList;
023    import java.util.Collection;
024    import java.util.Iterator;
025    import java.util.List;
026    
027    import javax.management.DynamicMBean;
028    import javax.management.InstanceAlreadyExistsException;
029    import javax.management.InstanceNotFoundException;
030    import javax.management.MBeanRegistrationException;
031    import javax.management.MBeanServer;
032    import javax.management.MalformedObjectNameException;
033    import javax.management.NotCompliantMBeanException;
034    import javax.management.ObjectName;
035    
036    import org.apache.log4j.Logger;
037    import org.apache.wiki.Release;
038    import org.apache.wiki.WikiEngine;
039    import org.apache.wiki.api.engine.AdminBeanManager;
040    import org.apache.wiki.api.engine.PluginManager;
041    import org.apache.wiki.event.WikiEngineEvent;
042    import org.apache.wiki.event.WikiEvent;
043    import org.apache.wiki.event.WikiEventListener;
044    import org.apache.wiki.modules.WikiModuleInfo;
045    import org.apache.wiki.ui.admin.beans.CoreBean;
046    import org.apache.wiki.ui.admin.beans.PluginBean;
047    import org.apache.wiki.ui.admin.beans.SearchManagerBean;
048    import org.apache.wiki.ui.admin.beans.UserBean;
049    
050    
051    /**
052     *  Provides a manager class for all AdminBeans within JSPWiki.  This class also manages registration for any 
053     *  AdminBean which is also a JMX bean.
054     *
055     *  @since  2.5.52
056     */
057    public class DefaultAdminBeanManager implements WikiEventListener, AdminBeanManager {
058        
059        private WikiEngine m_engine;
060        private ArrayList< AdminBean >  m_allBeans;
061    
062        private MBeanServer m_mbeanServer = null;
063    
064        private static Logger log = Logger.getLogger(DefaultAdminBeanManager.class);
065    
066        public DefaultAdminBeanManager( WikiEngine engine ) {
067            log.info("Using JDK 1.5 Platform MBeanServer");
068            m_mbeanServer = MBeanServerFactory15.getServer();
069    
070            m_engine = engine;
071    
072            if( m_mbeanServer != null ) {
073                log.info( m_mbeanServer.getClass().getName() );
074                log.info( m_mbeanServer.getDefaultDomain() );
075            }
076    
077            m_engine.addWikiEventListener( this );
078            initialize();
079        }
080    
081        /* (non-Javadoc)
082         * @see org.apache.wiki.ui.admin.AdminBeanManager#initialize()
083         */
084        @Override
085        public void initialize() {
086            reload();
087        }
088    
089        private String getJMXTitleString( int title ) {
090            switch( title ) {
091                case AdminBean.CORE:
092                    return "Core";
093    
094                case AdminBean.EDITOR:
095                    return "Editors";
096    
097                case AdminBean.UNKNOWN:
098                default:
099                    return "Unknown";
100            }
101        }
102    
103    
104        /**
105         *  Register an AdminBean.  If the AdminBean is also a JMX MBean, it also gets registered to the MBeanServer 
106         *  we've found.
107         *
108         *  @param ab AdminBean to register.
109         */
110        private void registerAdminBean( AdminBean ab ) {
111            try {
112                if( ab instanceof DynamicMBean && m_mbeanServer != null ) {
113                    ObjectName name = getObjectName( ab );
114    
115                    if( !m_mbeanServer.isRegistered( name ) ) {
116                        m_mbeanServer.registerMBean( ab, name );
117                    }
118                }
119    
120                m_allBeans.add( ab );
121    
122                log.info("Registered new admin bean "+ab.getTitle());
123            } catch( InstanceAlreadyExistsException e ) {
124                log.error("Admin bean already registered to JMX",e);
125            } catch( MBeanRegistrationException e ) {
126                log.error("Admin bean cannot be registered to JMX",e);
127            } catch( NotCompliantMBeanException e ) {
128                log.error("Your admin bean is not very good",e);
129            } catch( MalformedObjectNameException e ) {
130                log.error("Your admin bean name is not very good",e);
131            } catch( NullPointerException e ) {
132                log.error("Evil NPE occurred",e);
133            }
134        }
135    
136        private ObjectName getObjectName(AdminBean ab) throws MalformedObjectNameException {
137            String component = getJMXTitleString( ab.getType() );
138            String title     = ab.getTitle();
139    
140            ObjectName name = new ObjectName( Release.APPNAME + ":component="+component+",name="+title );
141            return name;
142        }
143    
144        /**
145         *  Registers all the beans from a collection of WikiModuleInfos.  If some of the beans
146         *  fail, logs the message and keeps going to the next bean.
147         *
148         *  @param c Collection of WikiModuleInfo instances
149         */
150        private void registerBeans( Collection c ) {
151            for( Iterator i = c.iterator(); i.hasNext(); ) {
152                String abname = ((WikiModuleInfo)i.next()).getAdminBeanClass();
153    
154                try {
155                    if( abname != null && abname.length() > 0 ) {
156                        Class< ? > abclass = Class.forName( abname );
157                        AdminBean ab = ( AdminBean ) abclass.newInstance();
158                        registerAdminBean( ab );
159                    }
160                } catch (ClassNotFoundException e) {
161                    log.error( e.getMessage(), e );
162                } catch (InstantiationException e) {
163                    log.error( e.getMessage(), e );
164                } catch (IllegalAccessException e) {
165                    log.error( e.getMessage(), e );
166                }
167            }
168    
169        }
170    
171        // FIXME: Should unload the beans first.
172        private void reload() {
173            m_allBeans = new ArrayList<AdminBean>();
174    
175            try {
176                registerAdminBean( new CoreBean(m_engine) );
177                registerAdminBean( new UserBean(m_engine) );
178                registerAdminBean( new SearchManagerBean(m_engine) );
179                registerAdminBean( new PluginBean(m_engine) );
180            } catch( NotCompliantMBeanException e ) {
181                log.error( e.getMessage(), e );
182            }
183            registerBeans( m_engine.getEditorManager().modules() );
184            PluginManager pm = m_engine.getPluginManager();
185            registerBeans( pm.modules() );
186        }
187    
188        /* (non-Javadoc)
189         * @see org.apache.wiki.ui.admin.AdminBeanManager#getAllBeans()
190         */
191        @Override
192        public List< AdminBean > getAllBeans() {
193            if( m_allBeans == null ) {
194                reload();
195            }
196    
197            return m_allBeans;
198        }
199    
200        /* (non-Javadoc)
201         * @see org.apache.wiki.ui.admin.AdminBeanManager#findBean(java.lang.String)
202         */
203        @Override
204        public AdminBean findBean( String id ) {
205            for( Iterator< AdminBean > i = m_allBeans.iterator(); i.hasNext(); ) {
206                AdminBean ab = i.next();
207    
208                if( ab.getId().equals(id) ) {
209                    return ab;
210                }
211            }
212    
213            return null;
214        }
215    
216        /**
217         *  Provides a JDK 1.5-compliant version of the MBeanServerFactory. This will simply bind to the 
218         *  platform MBeanServer.
219         */
220        private static final class MBeanServerFactory15 {
221            private MBeanServerFactory15()
222            {}
223    
224            public static MBeanServer getServer() {
225                return ManagementFactory.getPlatformMBeanServer();
226            }
227        }
228    
229        /**
230         *  Returns the type identifier for a string type.
231         *
232         *  @param type A type string.
233         *  @return A type value.
234         */
235        @Override
236        public int getTypeFromString( String type ) {
237            if( "core".equals( type ) ) {
238                return AdminBean.CORE;
239            } else if( "editors".equals( type ) ) {
240                return AdminBean.EDITOR;
241            }
242    
243            return AdminBean.UNKNOWN;
244        }
245    
246        /* (non-Javadoc)
247         * @see org.apache.wiki.ui.admin.AdminBeanManager#actionPerformed(org.apache.wiki.event.WikiEvent)
248         */
249        @Override
250        public void actionPerformed(WikiEvent event) {
251            if( event instanceof WikiEngineEvent ) {
252                if( ( ( WikiEngineEvent )event ).getType() == WikiEngineEvent.SHUTDOWN ) {
253                    for( Iterator< AdminBean > i = m_allBeans.iterator(); i.hasNext(); ) {
254                        try {
255                            AdminBean ab = i.next();
256                            ObjectName on = getObjectName( ab );
257                            if( m_mbeanServer.isRegistered( on ) ) {
258                                m_mbeanServer.unregisterMBean(on);
259                                log.info("Unregistered AdminBean "+ab.getTitle());
260                            }
261                        } catch( MalformedObjectNameException e ) {
262                            log.error("Malformed object name when unregistering",e);
263                        } catch (InstanceNotFoundException e) {
264                            log.error("Object was registered; yet claims that it's not there",e);
265                        } catch (MBeanRegistrationException e) {
266                            log.error("Registration exception while unregistering",e);
267                        }
268                    }
269                }
270            }
271        }
272        
273    }