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.mx.interceptor;
023:
024: import java.util.Hashtable;
025: import java.util.Set;
026:
027: import javax.management.InstanceAlreadyExistsException;
028: import javax.management.MBeanOperationInfo;
029: import javax.management.MBeanParameterInfo;
030: import javax.management.MBeanServer;
031: import javax.management.MalformedObjectNameException;
032: import javax.management.ObjectName;
033: import javax.management.modelmbean.ModelMBean;
034: import javax.management.modelmbean.ModelMBeanInfo;
035: import javax.management.modelmbean.ModelMBeanInfoSupport;
036: import javax.management.modelmbean.ModelMBeanOperationInfo;
037:
038: import org.jboss.logging.Logger;
039: import org.jboss.mx.modelmbean.ModelMBeanConstants;
040: import org.jboss.mx.modelmbean.RequiredModelMBeanInstantiator;
041: import org.jboss.mx.server.Invocation;
042: import org.jboss.mx.service.ServiceConstants;
043: import org.jboss.mx.util.AgentID;
044:
045: /**
046: * Base class for shared interceptors. This class provides some default method
047: * implementations for shared interceptors.
048: *
049: * @see org.jboss.mx.interceptor.SharedInterceptor
050: * @see org.jboss.mx.server.MBeanInvoker
051: *
052: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
053: * @version $Revision: 57200 $
054: */
055: public abstract class AbstractSharedInterceptor extends
056: AbstractInterceptor implements SharedInterceptor {
057:
058: /**
059: * MBean server reference for shared interceptors.
060: */
061: protected MBeanServer server = null;
062:
063: /**
064: * Object name of this interceptor. Shared interceptors must always contain
065: * a valid object name.
066: */
067: protected ObjectName objectName = null;
068:
069: // Constructors --------------------------------------------------
070:
071: /**
072: * Constructs a new shared interceptor instance. The interceptor is not
073: * automatically registered to the MBean server. Notice that the interceptor
074: * name must be set before the call to {@link #register} method. Shared
075: * interceptor names must be unique within the MBean server.
076: */
077: public AbstractSharedInterceptor() {
078: }
079:
080: /**
081: * Constructs a new shared interceptor instance with a given name. The interceptor
082: * is not automatically registered to the MBean server. Notice that the
083: * shared interceptor name must be unique name among all shared interceptors
084: * within the MBean server.
085: *
086: * @param name name of this interceptor
087: *
088: * @throws IllegalArgumentException if name contains <tt>null</tt> reference
089: */
090: public AbstractSharedInterceptor(String name) {
091: super (name);
092: }
093:
094: // SharedInterceptor implementation ------------------------------
095:
096: public ObjectName getObjectName() {
097: return objectName;
098: }
099:
100: public MBeanServer getMBeanServer() {
101: return server;
102: }
103:
104: /**
105: * Registers the interceptor to the MBean server. <p>
106: *
107: * The interceptor is registered under the
108: * {@link org.jboss.mx.service.ServiceConstants#JBOSSMX_DOMAIN JBOSSMX_DOMAIN}
109: * name. An interceptor's object name contains a <tt>type</tt> property and
110: * a <tt>name</tt> property. Property <tt>type</tt> always contains string
111: * <tt>'Interceptor'</tt> as its value. Interceptor's name is used as a value
112: * for the <tt>name</tt> property. Therefore, an interceptor created with
113: * name <tt>'Bart'</tt> can be found from the MBean server under object name: <br><pre>
114: *
115: * {@link org.jboss.mx.service.ServiceConstants#JBOSSMX_DOMAIN JBOSSMX_DOMAIN}:type=Interceptor,name=Bart,*
116: *
117: * </pre>
118: *
119: * If the log reference has not been set for this interceptor when it is
120: * registered, this implementation will register a log MBean via the system
121: * log manager under {@link org.jboss.mx.service.ServiceConstants#JBOSSMX_DOMAIN JBOSSMX}
122: * domain (see {@link org.jboss.mx.logging.SystemLogManager SystemLogManager}
123: * for details). The log instance's name will match the pattern: <br><pre>
124: *
125: * "JBossMX.Interceptor.<interceptor name>"
126: *
127: * </pre>
128: *
129: * @param server MBean server where this shared interceptor is registered
130: */
131: public synchronized ObjectName register(MBeanServer server)
132: throws InterceptorNameConflictException {
133:
134: // store MBean server reference
135: this .server = server;
136:
137: // check if log instance has been set
138: if (log == null)
139: log = Logger.getLogger("JBossMX.Interceptor." + name);
140:
141: try {
142: // store the object name for later use
143: objectName = createObjectName();
144:
145: // query the server for this name
146: Set names = server
147: .queryNames(objectName, null /* NO QUERY EXPR. */);
148:
149: // if the query returns a non empty set, throw an exception
150: if (names.size() > 0)
151: throw new InterceptorNameConflictException(
152: "A shared interceptor named '" + name
153: + "' already registered "
154: + "to this MBean server ("
155: + AgentID.get(server) + ")");
156:
157: // register the interceptor to server
158: ModelMBean rmm = RequiredModelMBeanInstantiator
159: .instantiate();
160: rmm
161: .setManagedResource(this ,
162: ModelMBeanConstants.OBJECT_REF);
163: rmm.setModelMBeanInfo(getManagementInterface());
164: server.registerMBean(rmm, objectName);
165:
166: // mark the interceptor as shared
167: isShared = true;
168: }
169:
170: catch (InstanceAlreadyExistsException e) {
171: // we already checked that the instance doesn't exist with a query,
172: // however it is possible it was created by another thread before we
173: // actually had a chance to register
174: throw new InterceptorNameConflictException(
175: "A shared interceptor named '" + name
176: + "' already registered "
177: + "to this MBean server ("
178: + AgentID.get(server) + ")");
179: }
180:
181: catch (Exception e) {
182: // anything else indicates there's something much more wrong if
183: // we can't register a simple MBean, so just log an error
184: if (log != null)
185: log.error(e.toString(), e);
186: }
187:
188: return objectName;
189: }
190:
191: /**
192: * This method is part of the interceptor MBean's registration lifecycle.
193: * It is called before the MBean is registered to the server. Concrete
194: * interceptor implementations can override this method to provide
195: * initialization code that should be executed before the interceptor
196: * is registered. <p>
197: *
198: * Any exception that is propagated from this method to its caller will
199: * cancel the interceptor registration.
200: *
201: * @throws Exception if you want to cancel the interceptor registration
202: */
203: public void init() throws Exception {
204: }
205:
206: /**
207: * This method is part of the interceptor MBean's registration lifecycle.
208: * It is called after the MBean is registered to the server. Concrete
209: * interceptor implementations can override this method to provide
210: * initialization code that should be executed once the MBean server and
211: * object name references for this interceptor have been resolved.
212: */
213: public void start() {
214: }
215:
216: /**
217: * This method is part of the interceptor MBean's registration lifecycle.
218: * It is called before the MBean is unregistered from the server. Concrete
219: * interceptor implementations can override this method to provide
220: * cleanup code that should be executed before the interceptor is
221: * unregistered. <p>
222: *
223: * Any exception that is propagated from this method to its caller will
224: * cancel the interceptor unregistration.
225: *
226: * @throws Exception if you want to cancel the interceptor unregistration
227: */
228: public void stop() throws Exception {
229: }
230:
231: /**
232: * This method is part of the interceptor MBean's registration lifecycle.
233: * It is called after the MBean has been unregistered from the server. Concrete
234: * interceptor implementations can override this method to provide
235: * cleanup code that should be executed once the interceptor is no longer
236: * registered to the MBean server.
237: */
238: public void destroy() {
239: }
240:
241: // MBeanRegistration implementation ------------------------------
242:
243: public ObjectName preRegister(MBeanServer server, ObjectName oname)
244: throws Exception {
245: this .server = server;
246:
247: if (oname == null)
248: this .objectName = createObjectName();
249: else
250: this .objectName = oname;
251:
252: init();
253:
254: return objectName;
255: }
256:
257: public void postRegister(Boolean registrationSuccesful) {
258: isShared = true;
259:
260: start();
261: }
262:
263: public void preDeregister() throws Exception {
264: stop();
265:
266: isShared = false;
267: objectName = null;
268: }
269:
270: public void postDeregister() {
271: destroy();
272: }
273:
274: // AbstractInterceptor overrides ---------------------------------
275:
276: /**
277: * Shared interceptors allows their name to be set only before they have
278: * been registered to the MBean server. After that the name is fixed and
279: * any attempt to invoke this method to change the name will yield a
280: * IllegalArgumentException.
281: *
282: * @param name name of this shared interceptor
283: *
284: * @throws IllegalArgumentException if there was an attempt to change the
285: * name after the interceptor had been registered to the server
286: */
287: public synchronized void setName(String name) {
288: if (isShared())
289: throw new IllegalArgumentException(
290: "Cannot change the interceptor name. Already registered.");
291:
292: this .name = name;
293: }
294:
295: // Object overrides ----------------------------------------------
296:
297: /**
298: * Returns a string representation of this interceptor instance.
299: *
300: * @return string representation
301: */
302: public String toString() {
303: String className = getClass().getName();
304: int index = className.lastIndexOf('.');
305:
306: return className.substring((index < 0) ? 0 : index) + "["
307: + "name=" + name + "SHARED " + objectName + "]";
308: }
309:
310: // Protected -----------------------------------------------------
311:
312: /**
313: * Creates an object name for this interceptor. The object name contains a
314: * <tt>type</tt> property and a <tt>name</tt> property. Property <tt>type</tt>
315: * always contains string <tt>'Interceptor'</tt> as its value. Interceptor's
316: * name is used as a value for the <tt>name</tt> property. Therefore, an
317: * interceptor created with name <tt>'Bart'</tt> will generate an object name
318: * matching to pattern: <br><pre>
319: *
320: * {@link org.jboss.mx.service.ServiceConstants#JBOSSMX_DOMAIN JBOSSMX_DOMAIN}:type=Interceptor,name=Bart,*
321: *
322: * </pre>
323: *
324: * @return generated object name for this interceptor
325: *
326: * @throws MalformedObjectNameException if the object name could not be
327: * created
328: */
329: protected ObjectName createObjectName()
330: throws MalformedObjectNameException {
331: // create the object name for this shared interceptor
332: Hashtable props = new Hashtable(2);
333: props.put("type", "Interceptor");
334: props.put("name", name);
335: props.put("ID", "0");
336:
337: return new ObjectName(ServiceConstants.JBOSSMX_DOMAIN, props);
338: }
339:
340: // Private -------------------------------------------------------
341:
342: private ModelMBeanInfo getManagementInterface() {
343: return new ModelMBeanInfoSupport(this .getClass().getName(), // resource object class name
344: "Interceptor invocation interface", // description of the MBean
345:
346: null, // attributes
347:
348: null, // constructors
349:
350: new ModelMBeanOperationInfo[] // operations
351: { new ModelMBeanOperationInfo("invoke", // name
352: "Shared interceptor invoke operation.", // description
353: new MBeanParameterInfo[] // arguments
354: { new MBeanParameterInfo("invocation", // name
355: Invocation.class.getName(), // type
356: "The invocation object." // description
357: ) }, Object.class.getName(), // return type
358: MBeanOperationInfo.ACTION_INFO // impact
359: ) },
360:
361: null // notifications
362: );
363: }
364:
365: }
|