001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.management;
023:
024: import java.lang.reflect.Constructor;
025: import java.lang.reflect.InvocationTargetException;
026: import java.lang.reflect.Method;
027: import java.security.AccessController;
028: import java.security.PrivilegedActionException;
029: import java.security.PrivilegedExceptionAction;
030: import java.util.ArrayList;
031: import java.util.HashMap;
032: import java.util.Map;
033: import javax.management.loading.ClassLoaderRepository;
034:
035: import org.jboss.mx.server.ServerConstants;
036: import org.jboss.mx.util.PropertyAccess;
037:
038: /**
039: * MBeanServerFactory is used to create instances of MBean servers.
040: *
041: * @see javax.management.MBeanServer
042: * @see javax.management.MBeanServerBuilder
043: *
044: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
045: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>.
046: * @author Scott.Stark@jboss.org
047: * @version $Revision: 57200 $
048: *
049: * <p><b>Revisions:</b>
050: *
051: * <p><b>20030806 Juha Lindfors:</b>
052: * <ul>
053: * <li>
054: * Attempts a reflected invoke to "releaseServer" method on the MBean server
055: * instance before letting go of the server reference. This allows the
056: * MBean server to do some clean up. Based on the patch submitted by
057: * Rod Burgett (Bug Tracker: #763378)
058: * </ul>
059: */
060: public class MBeanServerFactory {
061:
062: // Constants -----------------------------------------------------
063:
064: private static final MBeanServerPermission CREATE = new MBeanServerPermission(
065: "createMBeanServer", null);
066: private static final MBeanServerPermission FIND = new MBeanServerPermission(
067: "findMBeanServer", null);
068: private static final MBeanServerPermission NEW = new MBeanServerPermission(
069: "newMBeanServer", null);
070: private static final MBeanServerPermission RELEASE = new MBeanServerPermission(
071: "releaseMBeanServer", null);
072:
073: // Attributes ----------------------------------------------------
074:
075: /**
076: * Hold on to the server instances here (unless requested not to)
077: */
078: private static Map serverMap = new HashMap();
079:
080: // hide public constructor
081: private MBeanServerFactory() {
082: }
083:
084: // Public --------------------------------------------------------
085:
086: /**
087: * Releases the reference to an MBean server. A security permission check
088: * is made first if security manager has been installed.
089: *
090: * @param mbeanServer reference to the MBean server you want to release
091: */
092: public static void releaseMBeanServer(MBeanServer mbeanServer) {
093: checkPermission(RELEASE);
094: try {
095: String agentID = null;
096: /* Run the create using the jmx codebase priviledges since the
097: MBeanServerPermission(releaseMBeanServer) has passed.
098: */
099: final MBeanServer theServer = mbeanServer;
100: final ObjectName delegateName = new ObjectName(
101: ServerConstants.MBEAN_SERVER_DELEGATE);
102: try {
103: agentID = (String) AccessController
104: .doPrivileged(new PrivilegedExceptionAction() {
105: public Object run() throws Exception {
106: return (String) theServer.getAttribute(
107: delegateName, "MBeanServerId");
108: }
109: });
110: } catch (PrivilegedActionException e) {
111: Exception ex = e.getException();
112: if (ex instanceof JMException)
113: throw (JMException) ex;
114: else if (ex instanceof RuntimeException)
115: throw (RuntimeException) ex;
116: else {
117: JMException jex = new JMException(
118: "Unknown exception during getAttribute(MBeanServerId)");
119: jex.initCause(ex);
120: throw jex;
121: }
122: }
123:
124: Object server = serverMap.remove(agentID);
125:
126: try {
127: Method m = server.getClass().getMethod("releaseServer",
128: null);
129: m.invoke(server, null);
130: } catch (Exception ignored) {
131: // if the release fails, then it fails
132: }
133:
134: if (server == null)
135: throw new IllegalArgumentException(
136: "MBean server reference not found.");
137: } catch (MalformedObjectNameException e) {
138: throw new Error(e.toString());
139: } catch (JMException e) {
140: throw new Error("Cannot retrieve AgentID: " + e.toString());
141: }
142: }
143:
144: public static MBeanServer createMBeanServer() {
145: return createMBeanServer(ServerConstants.DEFAULT_DOMAIN);
146: }
147:
148: public static MBeanServer createMBeanServer(String domain) {
149: checkPermission(CREATE);
150: return createMBeanServer(domain, true);
151: }
152:
153: public static MBeanServer newMBeanServer() {
154: return newMBeanServer(ServerConstants.DEFAULT_DOMAIN);
155: }
156:
157: public static MBeanServer newMBeanServer(String domain) {
158: checkPermission(NEW);
159: return createMBeanServer(domain, false);
160: }
161:
162: public synchronized static ArrayList findMBeanServer(String agentId) {
163: checkPermission(FIND);
164: if (agentId != null) {
165: ArrayList list = new ArrayList(1);
166: Object server = serverMap.get(agentId);
167:
168: if (server != null)
169: list.add(server);
170:
171: return list;
172: }
173:
174: return new ArrayList(serverMap.values());
175: }
176:
177: /**
178: * Returns the classloader repository for an MBeanServer
179: *
180: * @param server the mbean server, pass null for the default loader repository
181: * shared by all mbeanservers
182: * @return the loader repository
183: */
184: public static ClassLoaderRepository getClassLoaderRepository(
185: MBeanServer server) {
186: return server.getClassLoaderRepository();
187: }
188:
189: // Private -------------------------------------------------------
190:
191: private static MBeanServer createMBeanServer(
192: final String defaultDomain, boolean registerServer) {
193: String builderClass = PropertyAccess.getProperty(
194: ServerConstants.MBEAN_SERVER_BUILDER_CLASS_PROPERTY,
195: ServerConstants.DEFAULT_MBEAN_SERVER_BUILDER_CLASS);
196:
197: try {
198: ClassLoader cl = Thread.currentThread()
199: .getContextClassLoader();
200: Class clazz = cl.loadClass(builderClass);
201: Constructor constructor = clazz
202: .getConstructor(new Class[0]);
203: final MBeanServerBuilder builder = (MBeanServerBuilder) constructor
204: .newInstance(new Object[0]);
205: final MBeanServerDelegate delegate = builder
206: .newMBeanServerDelegate();
207: /* Run the create using the jmx codebase priviledges since the
208: MBeanServerPermission(createMBeanServer) has passed.
209: */
210: MBeanServer server = null;
211: try {
212: server = (MBeanServer) AccessController
213: .doPrivileged(new PrivilegedExceptionAction() {
214: public Object run() throws Exception {
215: return builder.newMBeanServer(
216: defaultDomain, null, delegate);
217: }
218: });
219: } catch (PrivilegedActionException e) {
220: RuntimeException re = (RuntimeException) e
221: .getException();
222: throw re;
223: }
224:
225: if (registerServer) {
226: String agentID = delegate.getMBeanServerId();
227: serverMap.put(agentID, server);
228: }
229:
230: return server;
231: } catch (ClassNotFoundException e) {
232: throw new IllegalArgumentException(
233: "The MBean server builder implementation class "
234: + builderClass + " was not found: "
235: + e.toString());
236: } catch (NoSuchMethodException e) {
237: throw new IllegalArgumentException(
238: "The MBean server builder implementation class "
239: + builderClass
240: + " must contain a default constructor.");
241: } catch (InstantiationException e) {
242: throw new IllegalArgumentException(
243: "Cannot instantiate class " + builderClass + ": "
244: + e.toString());
245: } catch (IllegalAccessException e) {
246: throw new IllegalArgumentException(
247: "Unable to create the MBean server builder instance. Illegal access to class "
248: + builderClass + " constructor: "
249: + e.toString());
250: } catch (InvocationTargetException e) {
251: throw new RuntimeException(
252: "Unable to create the MBean server builder instance. Class "
253: + builderClass
254: + " has raised an exception in constructor: "
255: + e.getTargetException().toString());
256: }
257: }
258:
259: private static void checkPermission(MBeanServerPermission permission) {
260: SecurityManager security = System.getSecurityManager();
261: if (security == null)
262: return;
263: security.checkPermission(permission);
264: }
265:
266: }
|