1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22 package org.jboss.system;
23
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import javax.management.ObjectName;
29
30 import org.jboss.logging.Logger;
31 import org.jboss.mx.interceptor.AbstractInterceptor;
32 import org.jboss.mx.interceptor.DynamicInterceptor;
33 import org.jboss.mx.interceptor.Interceptor;
34 import org.jboss.mx.server.Invocation;
35
36 /**
37 * Helper class that can be used for writing MBean Services
38 * that dynamically hook-up an Interceptor to other (X)MBeans
39 * that have been configured as Interceptable.
40 *
41 * In a nutshell, call attach()/detach() from your
42 * createService()/destroyService() or startService()/stopService()
43 * pair methods to attach/detach an interceptor to the target mbean(s),
44 * then override invoke() to do something with the invocations.
45 *
46 * You may also provide your own Interceptor, in which case
47 * you should call attach(Interceptor).
48 *
49 * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
50 * @version $Revision: 57108 $
51 */
52 public abstract class InterceptorServiceMBeanSupport extends ServiceMBeanSupport
53 implements InterceptorServiceMBean
54 {
55 // Private Data --------------------------------------------------
56
57 /** The Interceptables to attach to */
58 private List interceptables;
59
60 /** The attached interceptor */
61 private Interceptor interceptor;
62
63 // Constructors -------------------------------------------------
64
65 /**
66 * Constructs an <tt>InterceptorServiceMBeanSupport</tt>.
67 */
68 public InterceptorServiceMBeanSupport()
69 {
70 super();
71 }
72
73 /**
74 * Constructs an <tt>InterceptorServiceMBeanSupport</tt>.
75 *
76 * Pass-through to ServiceMBeanSupport.
77 *
78 * @param type The class type to determine Logger name from.
79 */
80 public InterceptorServiceMBeanSupport(final Class type)
81 {
82 super(type);
83 }
84
85 /**
86 * Constructs an <tt>InterceptorServiceMBeanSupport</tt>.
87 *
88 * Pass-through to ServiceMBeanSupport.
89 *
90 * @param category The logger category name.
91 */
92 public InterceptorServiceMBeanSupport(final String category)
93 {
94 super(category);
95 }
96
97 /**
98 * Constructs an <tt>InterceptorServiceMBeanSupport</tt>.
99 *
100 * Pass-through to ServiceMBeanSupport.
101 *
102 * @param log The logger to use.
103 */
104 public InterceptorServiceMBeanSupport(final Logger log)
105 {
106 super(log);
107 }
108
109 // InterceptorServiceMBean ---------------------------------------
110
111 public void setInterceptables(List interceptables)
112 {
113 // copy
114 if (interceptables != null)
115 {
116 this.interceptables = new ArrayList(interceptables);
117 }
118 }
119
120 public List getInterceptables()
121 {
122 // return a copy
123 if (interceptables != null)
124 {
125 return new ArrayList(interceptables);
126 }
127 return null;
128 }
129
130 // Protected API -------------------------------------------------
131
132 /**
133 * Add our interceptor to the target Interceptables.
134 *
135 * Override invoke(Invocation) to handle the calls.
136 *
137 * @throws Exception thrown on any interceptor registration error
138 */
139 protected void attach() throws Exception
140 {
141 if (interceptor == null)
142 {
143 attach(new XMBeanInterceptor());
144 }
145 }
146
147 /**
148 * Add the provided interceptor to the target Interceptables.
149 *
150 * @param interceptor the interceptor to add
151 * @throws Exception thrown on any interceptor registration error
152 */
153 protected void attach(Interceptor interceptor) throws Exception
154 {
155 if (interceptor == null)
156 {
157 throw new IllegalArgumentException("Null interceptor");
158 }
159
160 // check we haven't attached already
161 if (this.interceptor != null)
162 {
163 throw new IllegalStateException("Interceptor already attached");
164 }
165
166 log.debug("Attaching interceptor: " + interceptor.getName());
167
168 // remember the interceptor
169 this.interceptor = interceptor;
170
171 // add the interceptor to the Interceptables; an exception
172 // will be thrown if any of them is not Interceptable,
173 // in which case detach() should be called.
174 if (interceptables != null)
175 {
176 Object[] params = new Object[] { interceptor };
177 String[] signature = new String[] { Interceptor.class.getName() };
178
179 for (Iterator i = interceptables.iterator(); i.hasNext(); )
180 {
181 ObjectName target = (ObjectName)i.next();
182 super.server.invoke(target,
183 DynamicInterceptor.ADD_INTERCEPTOR,
184 params,
185 signature);
186
187 log.debug("Interceptor attached to: '" + target + "'");
188 }
189 }
190 }
191
192 /**
193 * Remove the interceptor from the target Interceptables
194 */
195 protected void detach()
196 {
197 if (interceptor != null)
198 {
199 log.debug("Detaching interceptor: " + interceptor.getName());
200 if (interceptables != null)
201 {
202 Object[] params = new Object[] { interceptor };
203 String[] signature = new String[] { Interceptor.class.getName() };
204
205 for (Iterator i = interceptables.iterator(); i.hasNext(); )
206 {
207 ObjectName target = (ObjectName)i.next();
208 try
209 {
210 super.server.invoke(target,
211 DynamicInterceptor.REMOVE_INTERCEPTOR,
212 params,
213 signature);
214
215 log.debug("Interceptor detached from: '" + target + "'");
216 }
217 catch (Exception e)
218 {
219 log.debug("Caught exception while removing interceptor from '" +
220 target + "'", e);
221 }
222 }
223 }
224 interceptor = null;
225 }
226 }
227
228 /**
229 * Use this to forward the call
230 */
231 protected Object invokeNext(Invocation invocation) throws Throwable
232 {
233 // call the next in the interceptor chain,
234 // if nobody follows dispatch the call
235 Interceptor next = invocation.nextInterceptor();
236 if (next != null)
237 {
238 return next.invoke(invocation);
239 }
240 else
241 {
242 return invocation.dispatch();
243 }
244 }
245
246 // Override ------------------------------------------------------
247
248 /**
249 * Override
250 */
251 protected Object invoke(Invocation invocation) throws Throwable
252 {
253 return invokeNext(invocation);
254 }
255
256 // Private Inner Class -------------------------------------------
257
258 /**
259 * Simple Interceptor delegating to
260 * the invoke(Invocation) callback
261 */
262 private class XMBeanInterceptor extends AbstractInterceptor
263 {
264 public XMBeanInterceptor()
265 {
266 super("XMBeanInterceptor('" + InterceptorServiceMBeanSupport.this.getServiceName() + "')");
267 }
268
269 public Object invoke(Invocation invocation) throws Throwable
270 {
271 // delegate
272 return InterceptorServiceMBeanSupport.this.invoke(invocation);
273 }
274 }
275 }