001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source 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, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.management.j2ee;
031:
032: import com.caucho.jmx.IntrospectionMBean;
033: import com.caucho.jmx.Jmx;
034: import com.caucho.server.host.Host;
035: import com.caucho.server.webapp.WebApp;
036: import com.caucho.util.Alarm;
037:
038: import javax.management.MalformedObjectNameException;
039: import javax.management.ObjectName;
040: import java.util.Collection;
041: import java.util.Hashtable;
042: import java.util.Map;
043: import java.util.Set;
044: import java.util.TreeSet;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047:
048: /**
049: * Base class management interface for all managed objects.
050: */
051: abstract public class J2EEManagedObject {
052: private static final Logger log = Logger
053: .getLogger(J2EEManagedObject.class.getName());
054:
055: private static final String[] CONTEXT_KEYS = { "J2EEServer",
056: "Host", "J2EEApplication", "WebModule" };
057:
058: private final long _startTime;
059:
060: protected ObjectName _objectName;
061:
062: public J2EEManagedObject() {
063: _startTime = Alarm.getCurrentTime();
064: }
065:
066: public String getObjectName() {
067: return createObjectName().getCanonicalName();
068: }
069:
070: ObjectName createObjectName() {
071: if (_objectName == null) {
072: Hashtable<String, String> properties = new Hashtable<String, String>();
073:
074: try {
075: _objectName = createObjectName(properties);
076: } catch (MalformedObjectNameException ex) {
077: if (log.isLoggable(Level.FINE)) {
078: StringBuilder builder = new StringBuilder();
079:
080: builder.append('\'');
081: for (Map.Entry<String, String> entry : properties
082: .entrySet()) {
083: if (builder.length() > 0)
084: builder.append(',');
085:
086: builder.append(entry.getKey());
087: builder.append('=');
088: builder.append(entry.getValue());
089: }
090:
091: builder.append("' ");
092: builder.append(ex.toString());
093:
094: log.log(Level.FINE, builder.toString(), ex);
095: }
096: }
097: }
098:
099: return _objectName;
100: }
101:
102: /**
103: * Returns the value to use for the the `name' key of the
104: * ObjectName. The returned value is raw, users of the method must escape
105: * the returned value for use in an ObjectName.
106: */
107: abstract protected String getName();
108:
109: /**
110: * Returns true if the ObjectName should include the J2EEServer key.
111: * The default implementation returns true,
112: * derived class override to return false if there should not be a
113: * J2EEServer key.
114: */
115: protected boolean isJ2EEServer() {
116: return true;
117: }
118:
119: /**
120: * Returns true if the ObjectName should include the J2EEApplication key.
121: * The default implementation returns true,
122: * derived class override to return false if there should not be a
123: * J2EEApplication key.
124: */
125: protected boolean isJ2EEApplication() {
126: return true;
127: }
128:
129: protected String quote(String value) {
130: if (value == null)
131: return "null";
132: else if (value.length() == 0)
133: return "default";
134: else {
135: for (int i = 0; i < value.length(); i++) {
136: char ch = value.charAt(i);
137:
138: switch (ch) {
139: case ',':
140: case '=':
141: case '?':
142: case '"':
143: case ':':
144: return ObjectName.quote(value);
145: }
146: }
147:
148: return value;
149: }
150: }
151:
152: /**
153: * Creates the object name.
154: */
155: protected ObjectName createObjectName(
156: Hashtable<String, String> properties)
157: throws MalformedObjectNameException {
158: WebApp webApp = WebApp.getLocal();
159:
160: if (webApp != null) {
161: String contextPath = webApp.getContextPath();
162:
163: if (contextPath == null || contextPath.length() == 0)
164: contextPath = "/";
165:
166: properties.put("WebModule", quote(contextPath));
167: }
168:
169: Host host = Host.getLocal();
170:
171: if (isJ2EEApplication()) {
172: J2EEApplication j2eeApplication = J2EEApplication
173: .getLocal();
174:
175: if (j2eeApplication == null)
176: properties.put("J2EEApplication", quote("null"));
177: else
178: properties.put("J2EEApplication", quote(j2eeApplication
179: .getName()));
180: }
181:
182: if (host != null)
183: properties.put("Host", quote(host.getName()));
184:
185: if (isJ2EEServer()) {
186: J2EEServer j2eeServer = J2EEServer.getLocal();
187:
188: if (j2eeServer != null)
189: properties.put("J2EEServer",
190: quote(j2eeServer.getName()));
191: }
192:
193: String j2eeType;
194:
195: String className = getClass().getName();
196:
197: int lastDot = className.lastIndexOf('.');
198:
199: j2eeType = className.substring(lastDot + 1);
200:
201: properties.put("j2eeType", quote(j2eeType));
202:
203: String name = getName();
204:
205: if (name == null)
206: name = "null";
207:
208: properties.put("name", quote(name));
209:
210: return new ObjectName("j2ee", properties);
211: }
212:
213: /**
214: * Returns a list of ObjectNames that match the specified pattern composed
215: * of keys and values.
216: * The format of the arguments is <code>key1, value1, [keyN, valueN]</code>.
217: * The pattern does not need to include ",*", it is added automatically.
218: */
219: protected String[] queryObjectNames(String... pattern) {
220: TreeSet<String> objectNames = new TreeSet<String>();
221:
222: queryObjectNames(objectNames, pattern);
223:
224: return objectNames.toArray(new String[objectNames.size()]);
225: }
226:
227: /**
228: * Returns a list of ObjectNames that match the specified patterns.
229: * Each pattern is an array of keys and values.
230: * The pattern does not need to include ",*", it is added automatically.
231: */
232: protected String[] queryObjectNamesSet(String[][] patterns) {
233: TreeSet<String> objectNames = new TreeSet<String>();
234:
235: for (String[] pattern : patterns) {
236: queryObjectNames(objectNames, pattern);
237: }
238:
239: return objectNames.toArray(new String[objectNames.size()]);
240: }
241:
242: private void queryObjectNames(Collection<String> objectNames,
243: String[] pattern) {
244: try {
245: StringBuilder patternBuilder = new StringBuilder();
246:
247: patternBuilder.append("j2ee:");
248:
249: int length = pattern.length;
250:
251: for (int i = 0; i < length; i++) {
252: if (i != 0)
253: patternBuilder.append(',');
254:
255: String key = pattern[i];
256: String value = pattern[++i];
257:
258: patternBuilder.append(key);
259: patternBuilder.append('=');
260: patternBuilder.append(quote(value));
261: }
262:
263: for (String contextKey : CONTEXT_KEYS) {
264: if (patternBuilder.indexOf(contextKey) >= 0)
265: continue;
266:
267: String value = _objectName.getKeyProperty(contextKey);
268:
269: if (value != null) {
270: patternBuilder.append(',');
271: patternBuilder.append(contextKey);
272: patternBuilder.append('=');
273: patternBuilder.append(quote(value));
274: }
275: }
276:
277: patternBuilder.append(",*");
278:
279: ObjectName queryObjectName = new ObjectName(patternBuilder
280: .toString());
281:
282: Set<ObjectName> matchingObjectNames = Jmx
283: .getGlobalMBeanServer().queryNames(queryObjectName,
284: null);
285:
286: for (ObjectName matchingObjectName : matchingObjectNames)
287: objectNames.add(matchingObjectName.getCanonicalName());
288: } catch (Exception ex) {
289: if (log.isLoggable(Level.FINE))
290: log.log(Level.FINE, ex.toString(), ex);
291: }
292: }
293:
294: /**
295: * Returns true if the state is manageable
296: */
297: public boolean isStateManageable() {
298: return (this instanceof StateManageable);
299: }
300:
301: /**
302: * Returns true if the object provides statistics
303: */
304: public boolean isStatisticsProvider() {
305: return (this instanceof StatisticsProvider);
306: }
307:
308: /**
309: * Returns true if the object provides events
310: */
311: public boolean isEventProvider() {
312: return (this instanceof EventProvider);
313: }
314:
315: long getStartTime() {
316: return _startTime;
317: }
318:
319: /**
320: * Register a {@link J2EEManagedObject}.
321: * This method never throws an exception, any {@link Throwable} is caught
322: * and logged.
323: *
324: * @return the managed object if it is registered, null if there is an error.
325: */
326: public static <T extends J2EEManagedObject> T register(
327: T managedObject) {
328:
329: if (managedObject == null)
330: return null;
331:
332: ObjectName objectName = null;
333:
334: try {
335: objectName = managedObject.createObjectName();
336:
337: Object mbean = new IntrospectionMBean(managedObject,
338: managedObject.getClass(), true);
339:
340: // XXX: wait for 3.1
341: if (false) {
342: if (objectName != null)
343: Jmx.register(mbean, objectName);
344: }
345:
346: return managedObject;
347: } catch (Exception ex) {
348: if (log.isLoggable(Level.FINE))
349: log.log(Level.FINE, managedObject.getClass() + " "
350: + objectName + " " + ex.toString(), ex);
351:
352: return null;
353: }
354: }
355:
356: /**
357: * Unregister a {@link J2EEManagedObject}.
358: * This method never throws an exception, any {@link Throwable} is caught
359: * and logged.
360: *
361: * @param managedObject the managed object, can be null in which case
362: * nothing is done.
363: */
364: public static void unregister(J2EEManagedObject managedObject) {
365: if (managedObject == null)
366: return;
367:
368: ObjectName objectName = null;
369:
370: try {
371: objectName = managedObject.createObjectName();
372:
373: // XXX: wait for 3.1
374: if (false) {
375: Jmx.unregister(objectName);
376: }
377: } catch (Throwable ex) {
378: if (log.isLoggable(Level.FINEST))
379: log.log(Level.FINEST, managedObject.getClass() + " "
380: + objectName + " " + ex.toString(), ex);
381: }
382: }
383: }
|