001: /*
002: JSPWiki - a JSP-based WikiWiki clone.
003:
004: Copyright (C) 2001-2007 JSPWiki development group
005:
006: This program is free software; you can redistribute it and/or modify
007: it under the terms of the GNU Lesser General Public License as published by
008: the Free Software Foundation; either version 2.1 of the License, or
009: (at your option) any later version.
010:
011: This program is distributed in the hope that it will be useful,
012: but WITHOUT ANY WARRANTY; without even the implied warranty of
013: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: GNU Lesser General Public License for more details.
015:
016: You should have received a copy of the GNU Lesser General Public License
017: along with this program; if not, write to the Free Software
018: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020: package com.ecyrd.jspwiki.ui.admin;
021:
022: import java.lang.management.ManagementFactory;
023: import java.util.ArrayList;
024: import java.util.Collection;
025: import java.util.Iterator;
026: import java.util.List;
027:
028: import javax.management.*;
029:
030: import org.apache.commons.lang.SystemUtils;
031: import org.apache.log4j.Logger;
032:
033: import com.ecyrd.jspwiki.Release;
034: import com.ecyrd.jspwiki.WikiEngine;
035: import com.ecyrd.jspwiki.event.WikiEngineEvent;
036: import com.ecyrd.jspwiki.event.WikiEvent;
037: import com.ecyrd.jspwiki.event.WikiEventListener;
038: import com.ecyrd.jspwiki.modules.WikiModuleInfo;
039: import com.ecyrd.jspwiki.ui.admin.beans.CoreBean;
040: import com.ecyrd.jspwiki.ui.admin.beans.PluginBean;
041: import com.ecyrd.jspwiki.ui.admin.beans.SearchManagerBean;
042: import com.ecyrd.jspwiki.ui.admin.beans.UserBean;
043:
044: /**
045: * Provides a manager class for all AdminBeans within JSPWiki. This class
046: * also manages registration for any AdminBean which is also a JMX bean.
047: *
048: * @author Janne Jalkanen
049: * @since 2.5.52
050: */
051: public class AdminBeanManager implements WikiEventListener {
052: private WikiEngine m_engine;
053: private ArrayList m_allBeans;
054:
055: private MBeanServer m_mbeanServer = null;
056:
057: private static Logger log = Logger
058: .getLogger(AdminBeanManager.class);
059:
060: public AdminBeanManager(WikiEngine engine) {
061: if (SystemUtils.isJavaVersionAtLeast(1.5f)) {
062: log.info("Using JDK 1.5 Platform MBeanServer");
063: m_mbeanServer = MBeanServerFactory15.getServer();
064: } else {
065: log.info("Finding a JDK 1.4 -compatible MBeanServer.");
066: try {
067: m_mbeanServer = MBeanServerFactory14.getServer();
068: } catch (Exception e) {
069: log
070: .error("Unable to locate the JMX libraries from your classpath. "
071: + "Please make sure that \"jmxri.jar\" can be found in your WEB-INF/lib directory.");
072: }
073: }
074: m_engine = engine;
075:
076: if (m_mbeanServer != null) {
077: log.info(m_mbeanServer.getClass().getName());
078: log.info(m_mbeanServer.getDefaultDomain());
079: }
080:
081: m_engine.addWikiEventListener(this );
082: initialize();
083: }
084:
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: * Register an AdminBean. If the AdminBean is also a JMX MBean, it
105: * also gets registered to the MBeanServer we've found.
106: *
107: * @param ab AdminBean to register.
108: */
109: private void registerAdminBean(AdminBean ab) {
110: try {
111: if (ab instanceof DynamicMBean && m_mbeanServer != null) {
112: ObjectName name = getObjectName(ab);
113:
114: if (!m_mbeanServer.isRegistered(name)) {
115: m_mbeanServer.registerMBean(ab, name);
116: }
117: }
118:
119: m_allBeans.add(ab);
120:
121: log.info("Registered new admin bean " + ab.getTitle());
122: } catch (InstanceAlreadyExistsException e) {
123: log.error("Admin bean already registered to JMX", e);
124: } catch (MBeanRegistrationException e) {
125: log.error("Admin bean cannot be registered to JMX", e);
126: } catch (NotCompliantMBeanException e) {
127: log.error("Your admin bean is not very good", e);
128: } catch (MalformedObjectNameException e) {
129: log.error("Your admin bean name is not very good", e);
130: } catch (NullPointerException e) {
131: log.error("Evil NPE occurred", e);
132: }
133: }
134:
135: private ObjectName getObjectName(AdminBean ab)
136: throws MalformedObjectNameException {
137: String component = getJMXTitleString(ab.getType());
138: String title = ab.getTitle();
139:
140: ObjectName name = new ObjectName(Release.APPNAME
141: + ":component=" + component + ",name=" + title);
142: return name;
143: }
144:
145: /**
146: * Registers all the beans from a collection of WikiModuleInfos. If some of the beans
147: * fail, logs the message and keeps going to the next bean.
148: *
149: * @param c Collection of WikiModuleInfo instances
150: */
151: private void registerBeans(Collection c) {
152: for (Iterator i = c.iterator(); i.hasNext();) {
153: String abname = ((WikiModuleInfo) i.next())
154: .getAdminBeanClass();
155:
156: try {
157: if (abname != null && abname.length() > 0) {
158: Class abclass = Class.forName(abname);
159:
160: AdminBean ab = (AdminBean) abclass.newInstance();
161:
162: registerAdminBean(ab);
163: }
164: } catch (ClassNotFoundException e) {
165: // TODO Auto-generated catch block
166: e.printStackTrace();
167: } catch (InstantiationException e) {
168: // TODO Auto-generated catch block
169: e.printStackTrace();
170: } catch (IllegalAccessException e) {
171: // TODO Auto-generated catch block
172: e.printStackTrace();
173: }
174: }
175:
176: }
177:
178: // FIXME: Should unload the beans first.
179: private void reload() {
180: m_allBeans = new ArrayList();
181:
182: try {
183: registerAdminBean(new CoreBean(m_engine));
184: registerAdminBean(new UserBean(m_engine));
185: registerAdminBean(new SearchManagerBean(m_engine));
186: registerAdminBean(new PluginBean(m_engine));
187: } catch (NotCompliantMBeanException e) {
188: // TODO Auto-generated catch block
189: e.printStackTrace();
190: }
191: registerBeans(m_engine.getEditorManager().modules());
192: registerBeans(m_engine.getPluginManager().modules());
193: }
194:
195: /**
196: * Lists all administration beans which are currently known
197: * and instantiated.
198: *
199: * @return all AdminBeans known to the manager
200: */
201: public List getAllBeans() {
202: if (m_allBeans == null)
203: reload();
204:
205: return m_allBeans;
206: }
207:
208: /**
209: * Locates a bean based on the AdminBean.getId() out of all
210: * the registered beans.
211: *
212: * @param id ID
213: * @return An AdminBean, or null, if no such bean is found.
214: */
215: public AdminBean findBean(String id) {
216: for (Iterator i = m_allBeans.iterator(); i.hasNext();) {
217: AdminBean ab = (AdminBean) i.next();
218:
219: if (ab.getId().equals(id))
220: return ab;
221: }
222:
223: return null;
224: }
225:
226: /**
227: * A JDK 1.4 version of something which gets us the MBeanServer. It
228: * binds to the first server it can find.
229: *
230: * @author Janne Jalkanen
231: *
232: */
233: private static final class MBeanServerFactory14 {
234: private MBeanServerFactory14() {
235: }
236:
237: public static MBeanServer getServer() {
238: MBeanServer server;
239: ArrayList servers = MBeanServerFactory
240: .findMBeanServer(null);
241:
242: if (servers == null || servers.size() == 0) {
243: log.info("Creating a new MBeanServer...");
244: server = MBeanServerFactory
245: .createMBeanServer(Release.APPNAME);
246: } else {
247: server = (MBeanServer) servers.get(0);
248: }
249:
250: return server;
251: }
252: }
253:
254: /**
255: * Provides a JDK 1.5-compliant version of the MBeanServerFactory. This
256: * will simply bind to the platform MBeanServer.
257: *
258: * @author Janne Jalkanen
259: *
260: */
261: private static final class MBeanServerFactory15 {
262: private MBeanServerFactory15() {
263: }
264:
265: public static MBeanServer getServer() {
266: return ManagementFactory.getPlatformMBeanServer();
267: }
268: }
269:
270: /**
271: * Returns the type identifier for a string type.
272: *
273: * @param type A type string.
274: * @return A type value.
275: */
276: public static int getTypeFromString(String type) {
277: if (type.equals("core"))
278: return AdminBean.CORE;
279: else if (type.equals("editors"))
280: return AdminBean.EDITOR;
281:
282: return AdminBean.UNKNOWN;
283: }
284:
285: /**
286: * Unregisters AdminBeans upon SHUTDOWN event.
287: *
288: * @param event {@inheritDoc}
289: */
290: public void actionPerformed(WikiEvent event) {
291: if (event instanceof WikiEngineEvent) {
292: if (((WikiEngineEvent) event).getType() == WikiEngineEvent.SHUTDOWN) {
293: for (Iterator i = m_allBeans.iterator(); i.hasNext();) {
294: try {
295: AdminBean ab = (AdminBean) i.next();
296: ObjectName on = getObjectName(ab);
297: if (m_mbeanServer.isRegistered(on)) {
298: m_mbeanServer.unregisterMBean(on);
299: log.info("Unregistered AdminBean "
300: + ab.getTitle());
301: }
302: } catch (MalformedObjectNameException e) {
303: log
304: .error(
305: "Malformed object name when unregistering",
306: e);
307: } catch (InstanceNotFoundException e) {
308: log
309: .error(
310: "Object was registered; yet claims that it's not there",
311: e);
312: } catch (MBeanRegistrationException e) {
313: log
314: .error(
315: "Registration exception while unregistering",
316: e);
317: }
318: }
319: }
320: }
321: }
322: }
|