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 org.jboss.ejb3.service;
023:
024: import java.lang.reflect.Method;
025: import java.util.HashMap;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import javax.management.Attribute;
029: import javax.management.AttributeList;
030: import javax.management.AttributeNotFoundException;
031: import javax.management.Descriptor;
032: import javax.management.DynamicMBean;
033: import javax.management.InstanceNotFoundException;
034: import javax.management.InvalidAttributeValueException;
035: import javax.management.MBeanAttributeInfo;
036: import javax.management.MBeanException;
037: import javax.management.MBeanInfo;
038: import javax.management.MBeanOperationInfo;
039: import javax.management.MBeanParameterInfo;
040: import javax.management.MBeanServer;
041: import javax.management.ObjectName;
042: import javax.management.ReflectionException;
043: import javax.management.StandardMBean;
044: import javax.management.NotCompliantMBeanException;
045: import javax.management.modelmbean.DescriptorSupport;
046:
047: import org.jboss.mx.modelmbean.XMBean;
048: import org.jboss.mx.modelmbean.XMBeanConstants;
049:
050: import org.jboss.logging.Logger;
051: import org.jboss.util.Classes;
052:
053: /**
054: * @author <a href="mailto:kabir.khan@jboss.org">Kabir Khan</a>
055: * @version $Revision: 60233 $
056: */
057: public class ServiceMBeanDelegate implements DynamicMBean,
058: XMBeanConstants {
059: private static final Logger log = Logger
060: .getLogger(ServiceMBeanDelegate.class);
061:
062: MBeanServer server;
063: ServiceContainer container;
064: ObjectName serviceOn;
065: MBeanInfo mbeanInfo;
066:
067: HashMap<String, Method> getterMethods = new HashMap<String, Method>();
068: HashSet<String> getterBlackList = new HashSet<String>();
069: HashMap<String, Method> setterMethods = new HashMap<String, Method>();
070: HashSet<String> setterBlackList = new HashSet<String>();
071: HashMap<String, Method> operations = new HashMap<String, Method>();
072: HashSet<String> operationBlackList = new HashSet<String>();
073:
074: public ServiceMBeanDelegate(MBeanServer server,
075: ServiceContainer container, Class intf, ObjectName on) {
076: this .container = container;
077: this .server = server;
078: serviceOn = on;
079: StandardMBean mbean = null;
080: try {
081: mbean = new StandardMBean(container.getSingleton(), intf);
082: } catch (NotCompliantMBeanException e) {
083: throw new RuntimeException(e);
084: }
085: mbeanInfo = mbean.getMBeanInfo();
086: }
087:
088: public ServiceMBeanDelegate(MBeanServer server,
089: ServiceContainer container, String xmbean, ObjectName on) {
090: this .container = container;
091: this .server = server;
092: serviceOn = on;
093: XMBean mbean = null;
094: try {
095: Descriptor descriptor = new DescriptorSupport();
096: descriptor.setField(RESOURCE_REFERENCE, container
097: .getSingleton());
098: descriptor.setField(RESOURCE_TYPE, xmbean);
099: descriptor.setField(SAX_PARSER,
100: "org.apache.crimson.parser.XMLReaderImpl");
101:
102: mbean = new XMBean(descriptor, DESCRIPTOR);
103: } catch (NotCompliantMBeanException e) {
104: throw new RuntimeException(e);
105: } catch (javax.management.MBeanException e) {
106: throw new RuntimeException(e);
107: }
108: mbeanInfo = mbean.getMetaData();
109: }
110:
111: public ObjectName getObjectName() {
112: return serviceOn;
113: }
114:
115: public void register(ObjectName on, Class intf) throws Exception {
116: server.registerMBean(this , serviceOn);
117: }
118:
119: public void unregister() throws Exception {
120: server.unregisterMBean(serviceOn);
121: }
122:
123: public Object getAttribute(String attribute)
124: throws AttributeNotFoundException, MBeanException,
125: ReflectionException {
126: Method getter = getGetter(attribute);
127:
128: try {
129: return container.localInvoke(getter, new Object[0]);
130: } catch (Throwable t) {
131: if (t instanceof Exception)
132: throw new MBeanException((Exception) t);
133: else
134: throw new RuntimeException(t);
135: }
136: }
137:
138: public void setAttribute(Attribute attribute)
139: throws AttributeNotFoundException,
140: InvalidAttributeValueException, MBeanException,
141: ReflectionException {
142: Method setter = getSetter(attribute);
143: try {
144: container.localInvoke(setter, new Object[] { attribute
145: .getValue() });
146: } catch (Throwable t) {
147: if (t instanceof Exception)
148: throw new MBeanException((Exception) t);
149: else
150: throw new RuntimeException(t);
151: }
152: }
153:
154: public AttributeList getAttributes(String[] attributes) {
155: AttributeList list = new AttributeList();
156:
157: for (int i = 0; i < attributes.length; i++) {
158: try {
159: Object obj = getAttribute(attributes[i]);
160: list.add(new Attribute(attributes[i], obj));
161: } catch (Exception e) {
162: throw new RuntimeException("Error reading attribute: "
163: + attributes[i], e);
164: }
165: }
166: return list;
167: }
168:
169: public AttributeList setAttributes(AttributeList attributes) {
170: for (Iterator it = attributes.iterator(); it.hasNext();) {
171: Attribute attribute = (Attribute) it.next();
172: try {
173: setAttribute(attribute);
174: } catch (Exception e) {
175: throw new RuntimeException("Error setting attribute: "
176: + attribute, e);
177: }
178: }
179: return attributes;
180: }
181:
182: public Object invoke(String actionName, Object params[],
183: String signature[]) throws MBeanException,
184: ReflectionException {
185: if (log.isTraceEnabled())
186: log.trace("invoke: " + actionName);
187:
188: try {
189: // EJBTHREE-655: intercept lifecycle methods
190: // if(isMagicLifecycleMethod(actionName))
191: // {
192: // invokeMagicLifecycleMethod(actionName);
193: // return null;
194: // }
195:
196: Method operation = getOperation(actionName, signature);
197: return container.localInvoke(operation, params);
198: } catch (Throwable t) {
199: if (t instanceof Exception)
200: throw new MBeanException((Exception) t);
201: else
202: throw new RuntimeException(t);
203: }
204: }
205:
206: public MBeanInfo getMBeanInfo() {
207: return mbeanInfo;
208: }
209:
210: private String getOperationSignature(String actionName,
211: String[] types) {
212: //Not really the signature, just something unique
213: StringBuffer sig = new StringBuffer();
214: sig.append(actionName);
215:
216: if (types != null) {
217: for (int i = 0; i < types.length; i++) {
218: sig.append(" ");
219: sig.append(types[i]);
220: }
221: }
222: return sig.toString();
223: }
224:
225: private Method getGetter(String attribute)
226: throws AttributeNotFoundException {
227: Method getter = getterMethods.get(attribute);
228:
229: if (getter == null && !getterBlackList.contains(attribute)) {
230: synchronized (getterMethods) {
231: getter = getterMethods.get(attribute);
232: if (getter == null) {
233: try {
234: MBeanAttributeInfo[] attrInfos = mbeanInfo
235: .getAttributes();
236: for (int i = 0; i < attrInfos.length; i++) {
237: MBeanAttributeInfo attrInfo = attrInfos[i];
238: if (attrInfo.getName().equals(attribute)) {
239: if (!attrInfo.isReadable()) {
240: throw new AttributeNotFoundException(
241: "Attribute '"
242: + attribute
243: + "' is not writable in "
244: + container
245: .getBeanClass()
246: .getName());
247: }
248:
249: String getterName = ((attrInfo.isIs()) ? "is"
250: : "get")
251: + attribute;
252: getter = container.getBeanClass()
253: .getMethod(getterName);
254: getterMethods.put(attribute, getter);
255: }
256: }
257:
258: if (getter == null) {
259: throw new AttributeNotFoundException(
260: "No attribute called '" + attribute
261: + "' in "
262: + container.getBeanClass());
263: }
264: } catch (NoSuchMethodException e) {
265: throw new AttributeNotFoundException(
266: "Could not find getter for attribute '"
267: + attribute
268: + "' on "
269: + container.getBeanClass()
270: .getName());
271: } finally {
272: if (getter == null) {
273: getterBlackList.add(attribute);
274: }
275: }
276: }
277: }
278: }
279:
280: return getter;
281: }
282:
283: private Method getSetter(Attribute attribute)
284: throws AttributeNotFoundException {
285: String attrName = attribute.getName();
286: Method setter = setterMethods.get(attrName);
287:
288: if (setter == null && !setterBlackList.contains(attrName)) {
289: synchronized (setterMethods) {
290: setter = setterMethods.get(attrName);
291: if (setter == null) {
292: try {
293: MBeanAttributeInfo[] attrInfos = mbeanInfo
294: .getAttributes();
295: for (int i = 0; i < attrInfos.length; i++) {
296: MBeanAttributeInfo attrInfo = attrInfos[i];
297: if (attrInfo.getName().equals(attrName)) {
298: if (!attrInfo.isWritable()) {
299: throw new AttributeNotFoundException(
300: "Attribute '"
301: + attrName
302: + "' is not readable in "
303: + container
304: .getBeanClass()
305: .getName());
306: }
307:
308: String setterName = "set" + attrName;
309: Class type = Classes.loadClass(attrInfo
310: .getType());
311: setter = container.getBeanClass()
312: .getMethod(setterName, type);
313: setterMethods.put(attrName, setter);
314: }
315: }
316:
317: if (setter == null) {
318: throw new AttributeNotFoundException(
319: "No attribute called '" + attribute
320: + "' in "
321: + container.getBeanClass());
322: }
323: } catch (ClassNotFoundException e) {
324: throw new AttributeNotFoundException(
325: "Could not load setter type for attribute '"
326: + attrName
327: + "' on "
328: + container.getBeanClass()
329: .getName());
330: } catch (NoSuchMethodException e) {
331: throw new AttributeNotFoundException(
332: "Could not find setter for attribute '"
333: + attrName
334: + "' on "
335: + container.getBeanClass()
336: .getName());
337: } finally {
338: if (setter == null) {
339: setterBlackList.add(attrName);
340: }
341: }
342: }
343: }
344: }
345:
346: return setter;
347: }
348:
349: private Method getOperation(String actionName, String[] signature)
350: throws ReflectionException {
351: String opSig = getOperationSignature(actionName, signature);
352: Method operation = operations.get(actionName);
353:
354: if (operation == null && !setterBlackList.contains(opSig)) {
355: synchronized (setterMethods) {
356: operation = operations.get(opSig);
357: if (operation == null) {
358: try {
359: MBeanOperationInfo[] opInfos = mbeanInfo
360: .getOperations();
361: for (int i = 0; i < opInfos.length; i++) {
362: MBeanOperationInfo op = opInfos[i];
363: if (op.getName().equals(actionName)) {
364: boolean match = true;
365: MBeanParameterInfo[] sigTypes = op
366: .getSignature();
367: if (sigTypes.length == signature.length) {
368: for (int j = 0; j < sigTypes.length; j++) {
369: if (!sigTypes[j].getType()
370: .equals(signature[j])) {
371: match = false;
372: break;
373: }
374: }
375: }
376:
377: if (match) {
378: Class[] types = null;
379: if (signature.length > 0) {
380: types = new Class[signature.length];
381: for (int j = 0; j < signature.length; j++) {
382: types[j] = Classes
383: .loadClass(signature[j]);
384: }
385: } else {
386: types = new Class[0];
387: }
388: operation = container
389: .getBeanClass().getMethod(
390: actionName, types);
391: operations.put(opSig, operation);
392: }
393: }
394: }
395:
396: if (operation == null) {
397: throw new RuntimeException(
398: "No operation called '"
399: + actionName + "' in "
400: + container.getBeanClass());
401: }
402:
403: } catch (ClassNotFoundException e) {
404: throw new RuntimeException(
405: "Could not find type for operation '"
406: + actionName
407: + "' on "
408: + container.getBeanClass()
409: .getName());
410: } catch (NoSuchMethodException e) {
411: throw new RuntimeException(
412: "Could not find method for operation '"
413: + actionName
414: + "' on "
415: + container.getBeanClass()
416: .getName());
417: } finally {
418: if (operation == null) {
419: operationBlackList.add(opSig);
420: }
421: }
422: }
423: }
424: }
425:
426: return operation;
427: }
428:
429: /* EJBTHREE-655 has been postponed
430: protected void invokeMagicLifecycleMethod(String operationName) throws Exception
431: {
432: if(operationName.equals("create"))
433: container.create();
434: else if(operationName.equals("start"))
435: container.start();
436: else if(operationName.equals("stop"))
437: container.stop();
438: else if(operationName.equals("destroy"))
439: container.destroy();
440: else
441: throw new IllegalArgumentException("can't invoke " + operationName);
442: }
443:
444: protected boolean isMagicLifecycleMethod(String methodName)
445: {
446: if(methodName.equals("create"))
447: return true;
448: if(methodName.equals("start"))
449: return true;
450: if(methodName.equals("stop"))
451: return true;
452: if(methodName.equals("destroy"))
453: return true;
454: return false;
455: }
456: */
457: }
|