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, RegistryShutdownListener
053 {
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, MBeanServer beanServer,
077 ObjectNameBuilder objectNameBuilder, List beans)
078 {
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 {
096 Iterator iter = beans.iterator();
097 while (iter.hasNext())
098 {
099 MBeanRegistrationContribution mbeanReg = (MBeanRegistrationContribution) iter.next();
100 registerServiceAsMBean(mbeanReg.getObjectName(), mbeanReg.getServicePoint(), mbeanReg
101 .getStartMethod());
102 }
103 }
104
105 /**
106 * Registers a service as MBean. Retrieves an instance of the service by calling
107 * {@link ServicePoint#getService(Class)}
108 *
109 * @param objectName
110 * ObjectName for the MBean, if null the ObjectName is determined by the
111 * {@link ObjectNameBuilder}
112 * @param servicePoint
113 * ServicePoint
114 * @param startMethodName
115 * Name of the start method to call in the servicePoint after registration Can be
116 * null
117 */
118 private void registerServiceAsMBean(ObjectName objectName, ServicePoint servicePoint,
119 String startMethodName)
120 {
121 // By default the ObjectName is built by ObjectNameBuilder service
122 // but the name can be overriden in the contribution
123 if (objectName == null)
124 objectName = _objectNameBuilder.createServiceObjectName(servicePoint);
125
126 // Register the bean
127 Object mbean;
128 try
129 {
130 Class managementInterface = servicePoint.getServiceInterface();
131 // TODO: Check if ServiceModel is != pool and threaded
132 mbean = servicePoint.getService(managementInterface);
133 registerMBean(mbean, managementInterface, objectName);
134 }
135 catch (JMException e)
136 {
137 _errorHandler.error(
138 _log,
139 ManagementMessages.errorRegisteringMBean(objectName, e),
140 null,
141 e);
142 return;
143 }
144 // Call the start method if defined
145 try
146 {
147 if (startMethodName != null)
148 invokeStartMethod(mbean, startMethodName);
149 }
150 catch (InvocationTargetException e)
151 {
152 _errorHandler.error(_log, ManagementMessages.errorStartMethodFailed(
153 startMethodName,
154 objectName,
155 e.getTargetException()), null, e);
156 return;
157 }
158 catch (Exception e)
159 {
160 _errorHandler.error(_log, ManagementMessages.errorStartMethodFailed(
161 startMethodName,
162 objectName,
163 e), null, e);
164 return;
165 }
166 }
167
168 /**
169 * @throws InstanceAlreadyExistsException
170 * @throws MBeanRegistrationException
171 * @throws NotCompliantMBeanException
172 * @see MBeanRegistry#registerMBean(Object, Class, ObjectName)
173 */
174 public ObjectInstance registerMBean(Object obj, Class managementInterface, ObjectName objectName)
175 throws InstanceAlreadyExistsException, MBeanRegistrationException,
176 NotCompliantMBeanException
177 {
178 ObjectInstance instance = null;
179 try
180 {
181 if (_log.isDebugEnabled())
182 {
183 _log.debug("Trying to register MBean " + objectName);
184 }
185 instance = _beanServer.registerMBean(obj, objectName);
186 }
187 catch (NotCompliantMBeanException e)
188 {
189 if (_log.isDebugEnabled())
190 {
191 _log.debug("MBean " + objectName + " is not compliant. Registering"
192 + " using StandardMBean");
193 }
194 if (DynamicMBean.class.isAssignableFrom(obj.getClass()) || managementInterface == null)
195 throw e;
196 // if the object is a Standard MBean that is surrounded by
197 // a proxy or an interceptor it is not compliant since
198 // the naming conventions are not fulfilled.
199 // Now we use the StandardMBean class to adapt the MBean to the
200 // DynamicMBean interface which is not restricted by these
201 // naming conventions
202 StandardMBean standardMBean = new StandardMBean(obj, managementInterface);
203 instance = _beanServer.registerMBean(standardMBean, objectName);
204 }
205 _objectInstances.add(instance);
206 return instance;
207 }
208
209 /**
210 * @see org.apache.hivemind.management.MBeanRegistry#unregisterMBean(javax.management.ObjectName)
211 */
212 public void unregisterMBean(ObjectName objectName) throws InstanceNotFoundException,
213 MBeanRegistrationException
214 {
215 ObjectInstance instance = _beanServer.getObjectInstance(objectName);
216 _objectInstances.remove(instance);
217 _beanServer.unregisterMBean(objectName);
218 }
219
220 /**
221 * Calls the start method of an mbean
222 */
223 private void invokeStartMethod(Object mbean, String methodName) throws IllegalAccessException,
224 InvocationTargetException, NoSuchMethodException
225 {
226 Class serviceClass = mbean.getClass();
227 Method m = serviceClass.getMethod(methodName, null);
228 m.invoke(mbean, null);
229 }
230
231 /**
232 * Unregisters all registered MBeans
233 */
234 public void registryDidShutdown()
235 {
236 // Unregister objects in reversed order. Otherwise the
237 // Jsr 160 connector gets problems after the namingservice is unregistered
238 for (int i = _objectInstances.size() - 1; i >= 0; i--)
239 {
240 ObjectInstance objectInstance = (ObjectInstance) _objectInstances.get(i);
241 try
242 {
243 _beanServer.unregisterMBean(objectInstance.getObjectName());
244 }
245 catch (JMException e)
246 {
247 // Uncritical error, just warn
248 _log.warn(ManagementMessages.errorUnregisteringMBean(
249 objectInstance.getObjectName(),
250 e));
251 }
252 }
253 }
254
255 }