001: // Copyright 2005 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.hivemind.management.impl;
016:
017: import java.lang.reflect.InvocationTargetException;
018: import java.lang.reflect.Method;
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import javax.management.DynamicMBean;
024: import javax.management.InstanceAlreadyExistsException;
025: import javax.management.InstanceNotFoundException;
026: import javax.management.JMException;
027: import javax.management.MBeanRegistrationException;
028: import javax.management.MBeanServer;
029: import javax.management.NotCompliantMBeanException;
030: import javax.management.ObjectInstance;
031: import javax.management.ObjectName;
032: import javax.management.StandardMBean;
033:
034: import org.apache.commons.logging.Log;
035: import org.apache.hivemind.ErrorHandler;
036: import org.apache.hivemind.events.RegistryShutdownListener;
037: import org.apache.hivemind.internal.ServicePoint;
038: import org.apache.hivemind.management.MBeanRegistry;
039: import org.apache.hivemind.management.ManagementMessages;
040: import org.apache.hivemind.management.ObjectNameBuilder;
041:
042: /**
043: * Implementation of {@link MBeanRegistry}. Registers MBeans in an standard JMX MBeanServer Supports
044: * calling start methods, after the registration. MBeans can be provided as service references in a
045: * configuration. Standard MBeans must use the primitive service model. Any interceptor destroys JMX
046: * compliance due to naming conventions. Implements shutdown listener to unregisters all MBeans when
047: * the registry is shutdown
048: *
049: * @author Achim Huegen
050: * @since 1.1
051: */
052: public class MBeanRegistryImpl implements MBeanRegistry,
053: RegistryShutdownListener {
054: private ErrorHandler _errorHandler;
055:
056: private Log _log;
057:
058: private MBeanServer _beanServer;
059:
060: private ObjectNameBuilder _objectNameBuilder;
061:
062: private List _beans;
063:
064: // Holds all registered MBean instances
065: private List _objectInstances = new ArrayList();
066:
067: /**
068: * Creates new instance Registers all MBeans as defined in <code>beans</code>
069: *
070: * @param objectNameBuilder
071: * Service responsible for naming MBeans
072: * @param beans
073: * List with instances of {@link MBeanRegistrationContribution}. The specified
074: * services get registered as MBeans
075: */
076: public MBeanRegistryImpl(ErrorHandler errorHandler, Log log,
077: MBeanServer beanServer,
078: ObjectNameBuilder objectNameBuilder, List beans) {
079: _errorHandler = errorHandler;
080: _log = log;
081: _beanServer = beanServer;
082: _objectNameBuilder = objectNameBuilder;
083: _beans = beans;
084: if (_beans != null)
085: processContributions(_beans);
086: }
087:
088: /**
089: * Registers all services as MBeans, specified in the contribution to this service
090: *
091: * @param beans
092: * List of MBeanRegistrationContribution
093: */
094: private void processContributions(List beans) {
095: Iterator iter = beans.iterator();
096: while (iter.hasNext()) {
097: MBeanRegistrationContribution mbeanReg = (MBeanRegistrationContribution) iter
098: .next();
099: registerServiceAsMBean(mbeanReg.getObjectName(), mbeanReg
100: .getServicePoint(), mbeanReg.getStartMethod());
101: }
102: }
103:
104: /**
105: * Registers a service as MBean. Retrieves an instance of the service by calling
106: * {@link ServicePoint#getService(Class)}
107: *
108: * @param objectName
109: * ObjectName for the MBean, if null the ObjectName is determined by the
110: * {@link ObjectNameBuilder}
111: * @param servicePoint
112: * ServicePoint
113: * @param startMethodName
114: * Name of the start method to call in the servicePoint after registration Can be
115: * null
116: */
117: private void registerServiceAsMBean(ObjectName objectName,
118: ServicePoint servicePoint, String startMethodName) {
119: // By default the ObjectName is built by ObjectNameBuilder service
120: // but the name can be overriden in the contribution
121: if (objectName == null)
122: objectName = _objectNameBuilder
123: .createServiceObjectName(servicePoint);
124:
125: // Register the bean
126: Object mbean;
127: try {
128: Class managementInterface = servicePoint
129: .getServiceInterface();
130: // TODO: Check if ServiceModel is != pool and threaded
131: mbean = servicePoint.getService(managementInterface);
132: registerMBean(mbean, managementInterface, objectName);
133: } catch (JMException e) {
134: _errorHandler.error(_log, ManagementMessages
135: .errorRegisteringMBean(objectName, e), null, e);
136: return;
137: }
138: // Call the start method if defined
139: try {
140: if (startMethodName != null)
141: invokeStartMethod(mbean, startMethodName);
142: } catch (InvocationTargetException e) {
143: _errorHandler.error(_log, ManagementMessages
144: .errorStartMethodFailed(startMethodName,
145: objectName, e.getTargetException()), null,
146: e);
147: return;
148: } catch (Exception e) {
149: _errorHandler.error(_log, ManagementMessages
150: .errorStartMethodFailed(startMethodName,
151: objectName, e), null, e);
152: return;
153: }
154: }
155:
156: /**
157: * @throws InstanceAlreadyExistsException
158: * @throws MBeanRegistrationException
159: * @throws NotCompliantMBeanException
160: * @see MBeanRegistry#registerMBean(Object, Class, ObjectName)
161: */
162: public ObjectInstance registerMBean(Object obj,
163: Class managementInterface, ObjectName objectName)
164: throws InstanceAlreadyExistsException,
165: MBeanRegistrationException, NotCompliantMBeanException {
166: ObjectInstance instance = null;
167: try {
168: if (_log.isDebugEnabled()) {
169: _log.debug("Trying to register MBean " + objectName);
170: }
171: instance = _beanServer.registerMBean(obj, objectName);
172: } catch (NotCompliantMBeanException e) {
173: if (_log.isDebugEnabled()) {
174: _log.debug("MBean " + objectName
175: + " is not compliant. Registering"
176: + " using StandardMBean");
177: }
178: if (DynamicMBean.class.isAssignableFrom(obj.getClass())
179: || managementInterface == null)
180: throw e;
181: // if the object is a Standard MBean that is surrounded by
182: // a proxy or an interceptor it is not compliant since
183: // the naming conventions are not fulfilled.
184: // Now we use the StandardMBean class to adapt the MBean to the
185: // DynamicMBean interface which is not restricted by these
186: // naming conventions
187: StandardMBean standardMBean = new StandardMBean(obj,
188: managementInterface);
189: instance = _beanServer.registerMBean(standardMBean,
190: objectName);
191: }
192: _objectInstances.add(instance);
193: return instance;
194: }
195:
196: /**
197: * @see org.apache.hivemind.management.MBeanRegistry#unregisterMBean(javax.management.ObjectName)
198: */
199: public void unregisterMBean(ObjectName objectName)
200: throws InstanceNotFoundException,
201: MBeanRegistrationException {
202: ObjectInstance instance = _beanServer
203: .getObjectInstance(objectName);
204: _objectInstances.remove(instance);
205: _beanServer.unregisterMBean(objectName);
206: }
207:
208: /**
209: * Calls the start method of an mbean
210: */
211: private void invokeStartMethod(Object mbean, String methodName)
212: throws IllegalAccessException, InvocationTargetException,
213: NoSuchMethodException {
214: Class serviceClass = mbean.getClass();
215: Method m = serviceClass.getMethod(methodName, null);
216: m.invoke(mbean, null);
217: }
218:
219: /**
220: * Unregisters all registered MBeans
221: */
222: public void registryDidShutdown() {
223: // Unregister objects in reversed order. Otherwise the
224: // Jsr 160 connector gets problems after the namingservice is unregistered
225: for (int i = _objectInstances.size() - 1; i >= 0; i--) {
226: ObjectInstance objectInstance = (ObjectInstance) _objectInstances
227: .get(i);
228: try {
229: _beanServer.unregisterMBean(objectInstance
230: .getObjectName());
231: } catch (JMException e) {
232: // Uncritical error, just warn
233: _log.warn(ManagementMessages.errorUnregisteringMBean(
234: objectInstance.getObjectName(), e));
235: }
236: }
237: }
238:
239: }
|