001: /* JmxUtils
002: *
003: * Created on May 18, 2005
004: *
005: * Copyright (C) 2005 Internet Archive.
006: *
007: * This file is part of the Heritrix web crawler (crawler.archive.org).
008: *
009: * Heritrix is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU Lesser Public License as published by
011: * the Free Software Foundation; either version 2.1 of the License, or
012: * any later version.
013: *
014: * Heritrix is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
017: * GNU Lesser Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser Public License
020: * along with Heritrix; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
022: */
023: package org.archive.util;
024:
025: import java.net.InetSocketAddress;
026: import java.util.Arrays;
027: import java.util.Iterator;
028: import java.util.List;
029: import java.util.Map;
030: import java.util.logging.Level;
031: import java.util.logging.Logger;
032:
033: import javax.management.MBeanAttributeInfo;
034: import javax.management.MBeanOperationInfo;
035: import javax.management.MBeanParameterInfo;
036: import javax.management.MBeanServer;
037: import javax.management.MalformedObjectNameException;
038: import javax.management.ObjectName;
039: import javax.management.RuntimeOperationsException;
040: import javax.management.openmbean.CompositeType;
041: import javax.management.openmbean.InvalidOpenTypeException;
042: import javax.management.openmbean.OpenDataException;
043: import javax.management.openmbean.OpenMBeanAttributeInfo;
044: import javax.management.openmbean.OpenMBeanAttributeInfoSupport;
045: import javax.management.openmbean.OpenMBeanOperationInfo;
046: import javax.management.openmbean.OpenMBeanOperationInfoSupport;
047: import javax.management.openmbean.OpenMBeanParameterInfo;
048: import javax.management.openmbean.OpenMBeanParameterInfoSupport;
049: import javax.management.openmbean.OpenType;
050: import javax.management.openmbean.SimpleType;
051:
052: /**
053: * Static utility used by JMX.
054: * @author stack
055: * @version $Date: 2005-12-15 00:35:44 +0000 (Thu, 15 Dec 2005) $, $Revision: 4022 $
056: */
057: public class JmxUtils {
058: private static final Logger LOGGER = Logger
059: .getLogger(JmxUtils.class.getName());
060: public static final String TYPE = "type";
061: public static final String SERVICE = "CrawlService";
062: public static final String JOB = SERVICE + ".Job";
063: public static final String NAME = "name";
064: public static final String HOST = "host";
065: public static final String JMX_PORT = "jmxport";
066: public static final String GUI_PORT = "guiport";
067: public static final String KEY = "key";
068:
069: /**
070: * Key for name of the Heritrix instance hosting a Job: i.e. the
071: * CrawlJob's host/'mother'.
072: */
073: public static final String MOTHER = "mother";
074:
075: public static final ObjectName MBEAN_SERVER_DELEGATE;
076: static {
077: try {
078: MBEAN_SERVER_DELEGATE = new ObjectName(
079: "JMImplementation:type=MBeanServerDelegate");
080: } catch (Exception e) {
081: e.printStackTrace();
082: throw new RuntimeException(e);
083: }
084: }
085:
086: private static final List OPENTYPES = Arrays
087: .asList(OpenType.ALLOWED_CLASSNAMES);
088:
089: protected JmxUtils() {
090: super ();
091: }
092:
093: /**
094: * Return a string suitable for logging on registration.
095: * @param mbeanName Mbean that got registered.
096: * @param mbeanServer Server we were registered to.
097: * @param registrationDone Whether we registered successfully or not.
098: * @return String suitable for logging.
099: */
100: public static String getLogRegistrationMsg(final String mbeanName,
101: final MBeanServer mbeanServer,
102: final boolean registrationDone) {
103: return mbeanName + (registrationDone ? " " : " NOT ")
104: + "registered to "
105: + JmxUtils.getServerDetail(mbeanServer);
106: }
107:
108: public static String getLogUnregistrationMsg(
109: final String mbeanName, final MBeanServer mbeanServer) {
110: return mbeanName + " unregistered from "
111: + JmxUtils.getServerDetail(mbeanServer);
112: }
113:
114: public static String getServerDetail(final MBeanServer server) {
115: ObjectName delegateName = null;
116: try {
117: delegateName = new ObjectName(
118: "JMImplementation:type=MBeanServerDelegate");
119: } catch (MalformedObjectNameException e) {
120: LOGGER.log(Level.SEVERE, "Failed to create ObjectName for "
121: + "JMImplementation:type=MBeanServerDelegate", e);
122: return null;
123: }
124: StringBuffer buffer = new StringBuffer("MBeanServerId=");
125: try {
126: buffer.append((String) server.getAttribute(delegateName,
127: "MBeanServerId"));
128: buffer.append(", SpecificationVersion=");
129: buffer.append((String) server.getAttribute(delegateName,
130: "SpecificationVersion"));
131: buffer.append(", ImplementationVersion=");
132: buffer.append((String) server.getAttribute(delegateName,
133: "ImplementationVersion"));
134: buffer.append(", SpecificationVendor=");
135: buffer.append((String) server.getAttribute(delegateName,
136: "SpecificationVendor"));
137: } catch (Exception e) {
138: LOGGER
139: .log(
140: Level.SEVERE,
141: "Failed gettting server detail for "
142: + "JMImplementation:type=MBeanServerDelegate",
143: e);
144: }
145: return buffer.toString();
146: }
147:
148: /**
149: * @param operationName
150: * Name of operation we're checking params on (Used in exception
151: * if one thrown).
152: * @param params
153: * Amount of params passed.
154: * @param count
155: * Count of params expected.
156: */
157: public static void checkParamsCount(String operationName,
158: Object[] params, int count) {
159: if ((params.length != count)) {
160: throw new RuntimeOperationsException(
161: new IllegalArgumentException("Cannot invoke "
162: + operationName + ": Passed "
163: + Integer.toString(params.length)
164: + " argument(s) " + "but expected "
165: + Integer.toString(count)),
166: "Wrong number of arguments passed: unable to invoke "
167: + operationName + " method");
168: }
169: }
170:
171: /**
172: * @param in MBeanOperation to convert.
173: * @return An OpenMBeanOperation version of the passed MBeanOperation.
174: */
175: public static OpenMBeanOperationInfo convertToOpenMBeanOperation(
176: MBeanOperationInfo in) {
177: return convertToOpenMBeanOperation(in, null, null);
178: }
179:
180: /**
181: * @param in MBeanOperation to convert.
182: * @param prefix A prefix to add to the name of new operation.
183: * @param returnType Return type to use in new operation. Use this
184: * parameter to override the passed <code>in</code> return type.
185: * @return An OpenMBeanOperation version of the passed MBeanOperation.
186: */
187: public static OpenMBeanOperationInfo convertToOpenMBeanOperation(
188: final MBeanOperationInfo in, final String prefix,
189: final OpenType returnType) {
190: MBeanParameterInfo[] params = in.getSignature();
191: OpenMBeanParameterInfo[] signature = new OpenMBeanParameterInfo[params.length];
192: for (int i = 0; i < params.length; i++) {
193: signature[i] = convertToOpenMBeanOperationInfo(params[i]);
194: }
195: return new OpenMBeanOperationInfoSupport(
196: ((prefix != null) ? prefix + in.getName() : in
197: .getName()), in.getDescription(), signature,
198: (returnType != null) ? returnType : getOpenType(in
199: .getReturnType()),
200: convertImpact(in.getImpact()));
201: }
202:
203: public static int convertImpact(final int impact) {
204: if (impact != MBeanOperationInfo.ACTION
205: && impact != MBeanOperationInfo.ACTION_INFO
206: && impact != MBeanOperationInfo.INFO) {
207: // Don't allow back MBeanOperationInfo.UNKNOWN impact.
208: return MBeanOperationInfo.ACTION_INFO;
209: }
210: return impact;
211: }
212:
213: /**
214: * @param in MBeanParameterInfo to convert to an OpenMBeanParameterInfo.
215: * @return OpenMBeanParameterInfo version of <code>in</code>
216: */
217: public static OpenMBeanParameterInfo convertToOpenMBeanOperationInfo(
218: MBeanParameterInfo in) {
219: return new OpenMBeanParameterInfoSupport(in.getName(), in
220: .getDescription(), getOpenType(in.getType()));
221: }
222:
223: public static boolean isOpenType(final Class c) {
224: return isOpenType(c.getName());
225: }
226:
227: public static boolean isOpenType(final String classname) {
228: return OPENTYPES.contains(classname);
229: }
230:
231: /**
232: * @param classString Java class name.
233: * @return Its OpenType equivalent.
234: */
235: public static OpenType getOpenType(final String classString) {
236: return getOpenType(classString, null);
237: }
238:
239: /**
240: * @param classString Java class name.
241: * @param defaultType If no equivalent found, use passed defaultType.
242: * @return Its OpenType equivalent.
243: */
244: public static OpenType getOpenType(String classString,
245: final OpenType defaultType) {
246: if (classString.equals("void")) {
247: return SimpleType.VOID;
248: }
249: if (!isOpenType(classString)) {
250: throw new InvalidOpenTypeException(classString);
251: }
252: if (classString.equals(String.class.getName())) {
253: return SimpleType.STRING;
254: } else if (classString.equals(Boolean.class.getName())) {
255: return SimpleType.BOOLEAN;
256: } else if (classString.equals(Long.class.getName())) {
257: return SimpleType.LONG;
258: } else if (classString.equals(Integer.class.getName())) {
259: return SimpleType.INTEGER;
260: } else if (classString.equals(Float.class.getName())) {
261: return SimpleType.FLOAT;
262: } else if (classString.equals(Double.class.getName())) {
263: return SimpleType.DOUBLE;
264: } else if (defaultType != null) {
265: return defaultType;
266: }
267: throw new RuntimeException("Unsupported type: " + classString);
268: }
269:
270: /**
271: * @param in AttributeInfo to convert.
272: * @return OpenMBeanAttributeInfo version of <code>in</code>.
273: */
274: public static OpenMBeanAttributeInfo convertToOpenMBeanAttribute(
275: MBeanAttributeInfo in) {
276: return convertToOpenMBeanAttribute(in, null);
277: }
278:
279: /**
280: * @param in AttributeInfo to convert.
281: * @param prefix Prefix to add to names of new attributes. If null, nothing
282: * is added.
283: * @return OpenMBeanAttributeInfo version of <code>in</code>.
284: */
285: public static OpenMBeanAttributeInfo convertToOpenMBeanAttribute(
286: final MBeanAttributeInfo in, final String prefix) {
287: return createOpenMBeanAttributeInfo(getOpenType(in.getType()),
288: in, prefix);
289: }
290:
291: /**
292: * @param type Type of new OpenMBeanAttributeInfo.
293: * @param in The MBeanAttributeInfo we're converting.
294: * @param prefix Prefix to add to name of new Attribute (If null, nothing
295: * is added).
296: * @return New OpenMBeanAttributeInfo based on <code>in</code>.
297: */
298: public static OpenMBeanAttributeInfo createOpenMBeanAttributeInfo(
299: final OpenType type, final MBeanAttributeInfo in,
300: final String prefix) {
301: return new OpenMBeanAttributeInfoSupport(
302: ((prefix != null) ? prefix + in.getName() : in
303: .getName()), in.getDescription(), type, in
304: .isReadable(), in.isWritable(), in.isIs());
305: }
306:
307: /**
308: * @param m A map to make a CompositeType of (Assumption is that order does
309: * not matter. If it does, pass a map of sorted keys).
310: * @param compositeTypeName Name to give created compositeType.
311: * @param compositeTypeDescription Description.
312: * @return CompositeType made by examination of passed TreeMap.
313: * @throws OpenDataException
314: */
315: public static CompositeType createCompositeType(final Map m,
316: final String compositeTypeName,
317: final String compositeTypeDescription)
318: throws OpenDataException {
319: String[] keys = new String[m.size()];
320: OpenType[] types = new OpenType[m.size()];
321: int index = 0;
322: for (final Iterator i = m.keySet().iterator(); i.hasNext();) {
323: String key = (String) i.next();
324: keys[index] = key;
325: types[index] = getOpenType(m.get(key).getClass().getName());
326: index++;
327: }
328: return new CompositeType(compositeTypeName,
329: compositeTypeDescription, keys, keys, types);
330: }
331:
332: public static InetSocketAddress extractAddress(final ObjectName name) {
333: return new InetSocketAddress(name.getKeyProperty(HOST), Integer
334: .parseInt(name.getKeyProperty(JMX_PORT)));
335: }
336:
337: /**
338: * Returns the UID portion of the name key property of
339: * an object name representing a "CrawlService.Job" bean.
340: * It is assumed that the name will have the format
341: * {crawl name}-{uid}.
342: * @param on A CrawlServer.Job object name.
343: * @return Uid for a CrawlServer.Job.
344: */
345: public static String getUid(final ObjectName on) {
346: String name = on.getKeyProperty(NAME);
347: return name.substring(name.indexOf("-") + 1);
348: }
349: }
|