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.ha.singleton;
23
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.security.InvalidParameterException;
27
28 import javax.management.InstanceNotFoundException;
29 import javax.management.MBeanException;
30 import javax.management.ObjectName;
31 import javax.management.ReflectionException;
32
33 /**
34 * A clustered singleton service that calls a configurable
35 * method on a target (m)bean, whenever the current node becomes
36 * the master. Correspondingly, it calls a configurable method
37 * on the target (m)bean, whenever the current node resigns from
38 * being the master.
39 *
40 * Optional string arguments may be passed to those methods.
41 *
42 * @author <a href="mailto:ivelin@apache.org">Ivelin Ivanov</a>
43 * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>
44 * @author <a href="mailto:mr@gedoplan.de">Marcus Redeker</a>
45 * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
46 * @author Brian Stansberry
47 *
48 * @version $Revision: 73754 $
49 */
50 public class HASingletonController extends HASingletonSupport
51 implements HASingletonControllerMBean
52 {
53 // Private Data --------------------------------------------------
54
55 private ObjectName mSingletonMBean;
56 private Object mSingleton;
57 private String mSingletonStartMethod = "startSingleton";
58 private String mSingletonStopMethod = "stopSingleton";
59 private String mSingletonStartMethodArgument;
60 private String mSingletonStopMethodArgument;
61
62 private static final Object[] NO_ARGS = new Object[0];
63 private static final String[] NO_TYPE_NAMES = new String[0];
64 private static final Class[] NO_TYPES = new Class[0];
65
66 // Constructors --------------------------------------------------
67
68 /**
69 * Default CTOR
70 */
71 public HASingletonController()
72 {
73 // empty
74 }
75
76 // Attributes ----------------------------------------------------
77
78 public Object getTarget()
79 {
80 return mSingleton;
81 }
82
83 public void setTarget(Object target)
84 {
85 this.mSingleton = target;
86 }
87
88 public ObjectName getTargetName()
89 {
90 return mSingletonMBean;
91 }
92
93 public void setTargetName(ObjectName targetObjectName)
94 {
95 this.mSingletonMBean = targetObjectName;
96 }
97
98 public String getTargetStartMethod()
99 {
100 return mSingletonStartMethod;
101 }
102
103 public void setTargetStartMethod(String targetStartMethod)
104 throws InvalidParameterException
105 {
106 if (targetStartMethod != null)
107 mSingletonStartMethod = targetStartMethod;
108 }
109
110
111 public String getTargetStopMethod()
112 {
113 return mSingletonStopMethod;
114 }
115
116 public void setTargetStopMethod(String targetStopMethod)
117 throws InvalidParameterException
118 {
119 if (targetStopMethod != null)
120 mSingletonStopMethod = targetStopMethod;
121 }
122
123 public String getTargetStartMethodArgument()
124 {
125 return mSingletonStartMethodArgument ;
126 }
127
128 public void setTargetStartMethodArgument(String targetStartMethodArgument)
129 {
130 mSingletonStartMethodArgument = targetStartMethodArgument;
131 }
132
133 public String getTargetStopMethodArgument()
134 {
135 return mSingletonStopMethodArgument ;
136 }
137
138 public void setTargetStopMethodArgument(String targetStopMethodArgument)
139 {
140 mSingletonStopMethodArgument = targetStopMethodArgument;
141 }
142
143 // HASingleton implementation ------------------------------------
144
145 /**
146 * Call the target start method
147 *
148 * @see org.jboss.ha.singleton.HASingletonSupport#startSingleton()
149 */
150 public void startSingleton()
151 {
152 super.startSingleton();
153
154 try
155 {
156 if (mSingleton != null)
157 {
158 invokeSingletonMethod(
159 mSingleton,
160 mSingletonStartMethod,
161 mSingletonStartMethodArgument
162 );
163 }
164 else if (mSingletonMBean != null)
165 {
166 invokeSingletonMBeanMethod(
167 mSingletonMBean,
168 mSingletonStartMethod,
169 mSingletonStartMethodArgument
170 );
171 }
172 else
173 {
174 log.warn("No singleton configured; cannot start");
175 }
176 }
177 catch (Exception e)
178 {
179 log.error("Controlled Singleton failed to become master", e);
180 }
181 }
182
183 /**
184 * Call the target stop method
185 *
186 * @see org.jboss.ha.singleton.HASingletonSupport#stopSingleton()
187 */
188 public void stopSingleton()
189 {
190 super.stopSingleton();
191
192 try
193 {
194 if (mSingleton != null)
195 {
196 invokeSingletonMethod(
197 mSingleton,
198 mSingletonStopMethod,
199 mSingletonStopMethodArgument
200 );
201 }
202 else if (mSingletonMBean != null)
203 {
204 invokeSingletonMBeanMethod(
205 mSingletonMBean,
206 mSingletonStopMethod,
207 mSingletonStopMethodArgument
208 );
209 }
210 else
211 {
212 log.warn("No singleton configured; cannot start");
213 }
214 }
215 catch (Exception e)
216 {
217 log.error("Controlled Singleton failed to resign from master position", e);
218 }
219 }
220
221 // Protected -----------------------------------------------------
222
223 protected Object invokeSingletonMethod(Object target,
224 String operationName, Object param)
225 throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
226 {
227 if (target != null && operationName != null)
228 {
229 Object[] params;
230 Class[] types;
231
232 if (param != null)
233 {
234 params = new Object[] { param };
235 types = new Class[] { param.getClass() };
236
237 log.debug("Calling operation: " + operationName +
238 "(" + param + "), on target: '" + target + "'");
239 }
240 else
241 {
242 params = NO_ARGS;
243 types = NO_TYPES;
244
245 log.debug("Calling operation: " + operationName +
246 "(), on target: '" + target + "'");
247 }
248
249 Method method = getTargetMethod(target, operationName, types);
250
251 return method.invoke(target, params);
252 }
253 else
254 {
255 log.debug("No configured target mbean or operation to call");
256
257 return null;
258 }
259 }
260
261 protected Object invokeSingletonMBeanMethod(ObjectName target,
262 String operationName, Object param)
263 throws InstanceNotFoundException, MBeanException, ReflectionException
264 {
265 if (target != null && operationName != null)
266 {
267 Object[] params;
268 String[] signature;
269
270 if (param != null)
271 {
272 params = new Object[] { param };
273 signature = new String[] { param.getClass().getName() };
274
275 log.debug("Calling operation: " + operationName +
276 "(" + param + "), on target: '" + target + "'");
277 }
278 else
279 {
280 params = NO_ARGS;
281 signature = NO_TYPE_NAMES;
282
283 log.debug("Calling operation: " + operationName +
284 "(), on target: '" + target + "'");
285 }
286
287 return server.invoke(target, operationName, params, signature);
288 }
289 else
290 {
291 log.debug("No configured target mbean or operation to call");
292
293 return null;
294 }
295 }
296
297 public static Method getTargetMethod(Object target, String methodName, Class[] types)
298 throws NoSuchMethodException
299 {
300 Class clazz = target.getClass();
301 NoSuchMethodException nsme = null;
302 while (clazz != null)
303 {
304 try
305 {
306 Method method = clazz.getDeclaredMethod(methodName, types);
307 return method;
308 }
309 catch (NoSuchMethodException e)
310 {
311 // Cache the one from the top level class
312 if (nsme == null)
313 {
314 nsme = e;
315 }
316 // Keep searching
317 clazz = clazz.getSuperclass();
318 }
319 }
320 throw nsme;
321 }
322 }