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 */
019package org.apache.wiki.ui.admin;
020
021import java.lang.management.ManagementFactory;
022import java.util.ArrayList;
023import java.util.Collection;
024import java.util.Iterator;
025import java.util.List;
026
027import javax.management.DynamicMBean;
028import javax.management.InstanceAlreadyExistsException;
029import javax.management.InstanceNotFoundException;
030import javax.management.MBeanRegistrationException;
031import javax.management.MBeanServer;
032import javax.management.MalformedObjectNameException;
033import javax.management.NotCompliantMBeanException;
034import javax.management.ObjectName;
035
036import org.apache.log4j.Logger;
037import org.apache.wiki.Release;
038import org.apache.wiki.WikiEngine;
039import org.apache.wiki.api.engine.AdminBeanManager;
040import org.apache.wiki.event.WikiEngineEvent;
041import org.apache.wiki.event.WikiEvent;
042import org.apache.wiki.event.WikiEventListener;
043import org.apache.wiki.modules.WikiModuleInfo;
044import org.apache.wiki.ui.admin.beans.CoreBean;
045import org.apache.wiki.ui.admin.beans.FilterBean;
046import org.apache.wiki.ui.admin.beans.PluginBean;
047import org.apache.wiki.ui.admin.beans.SearchManagerBean;
048import 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 */
057public 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< WikiModuleInfo > c ) {
151        for( Iterator< WikiModuleInfo > i = c.iterator(); i.hasNext(); ) {
152            String abname = 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            registerAdminBean( new FilterBean( m_engine ) );
181        } catch( NotCompliantMBeanException e ) {
182            log.error( e.getMessage(), e );
183        }
184        registerBeans( m_engine.getEditorManager().modules() );
185        registerBeans( m_engine.getPluginManager().modules() );
186        registerBeans( m_engine.getFilterManager().modules() );
187    }
188
189    /* (non-Javadoc)
190     * @see org.apache.wiki.ui.admin.AdminBeanManager#getAllBeans()
191     */
192    @Override
193    public List< AdminBean > getAllBeans() {
194        if( m_allBeans == null ) {
195            reload();
196        }
197
198        return m_allBeans;
199    }
200
201    /* (non-Javadoc)
202     * @see org.apache.wiki.ui.admin.AdminBeanManager#findBean(java.lang.String)
203     */
204    @Override
205    public AdminBean findBean( String id ) {
206        for( Iterator< AdminBean > i = m_allBeans.iterator(); i.hasNext(); ) {
207            AdminBean ab = i.next();
208
209            if( ab.getId().equals(id) ) {
210                return ab;
211            }
212        }
213
214        return null;
215    }
216
217    /**
218     *  Provides a JDK 1.5-compliant version of the MBeanServerFactory. This will simply bind to the
219     *  platform MBeanServer.
220     */
221    private static final class MBeanServerFactory15 {
222        private MBeanServerFactory15()
223        {}
224
225        public static MBeanServer getServer() {
226            return ManagementFactory.getPlatformMBeanServer();
227        }
228    }
229
230    /**
231     *  Returns the type identifier for a string type.
232     *
233     *  @param type A type string.
234     *  @return A type value.
235     */
236    @Override
237    public int getTypeFromString( String type ) {
238        if( "core".equals( type ) ) {
239            return AdminBean.CORE;
240        } else if( "editors".equals( type ) ) {
241            return AdminBean.EDITOR;
242        }
243
244        return AdminBean.UNKNOWN;
245    }
246
247    /* (non-Javadoc)
248     * @see org.apache.wiki.ui.admin.AdminBeanManager#actionPerformed(org.apache.wiki.event.WikiEvent)
249     */
250    @Override
251    public void actionPerformed(WikiEvent event) {
252        if( event instanceof WikiEngineEvent ) {
253            if( ( ( WikiEngineEvent )event ).getType() == WikiEngineEvent.SHUTDOWN ) {
254                for( Iterator< AdminBean > i = m_allBeans.iterator(); i.hasNext(); ) {
255                    try {
256                        AdminBean ab = i.next();
257                        ObjectName on = getObjectName( ab );
258                        if( m_mbeanServer.isRegistered( on ) ) {
259                            m_mbeanServer.unregisterMBean(on);
260                            log.info("Unregistered AdminBean "+ab.getTitle());
261                        }
262                    } catch( MalformedObjectNameException e ) {
263                        log.error("Malformed object name when unregistering",e);
264                    } catch (InstanceNotFoundException e) {
265                        log.error("Object was registered; yet claims that it's not there",e);
266                    } catch (MBeanRegistrationException e) {
267                        log.error("Registration exception while unregistering",e);
268                    }
269                }
270            }
271        }
272    }
273
274}