1 /*
2 * JBoss, Home of Professional Open Source.
3 * Copyright 2008, Red Hat Middleware LLC, and individual contributors
4 * as indicated by the @author tags. See the copyright.txt file in the
5 * distribution for a 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: 81001 $
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 // Attributes ----------------------------------------------------
67
68 public Object getTarget()
69 {
70 return this.mSingleton;
71 }
72
73 public void setTarget(Object target)
74 {
75 this.mSingleton = target;
76 }
77
78 public ObjectName getTargetName()
79 {
80 return this.mSingletonMBean;
81 }
82
83 public void setTargetName(ObjectName targetObjectName)
84 {
85 this.mSingletonMBean = targetObjectName;
86 }
87
88 public String getTargetStartMethod()
89 {
90 return this.mSingletonStartMethod;
91 }
92
93 public void setTargetStartMethod(String targetStartMethod)
94 throws InvalidParameterException
95 {
96 if (targetStartMethod != null)
97 {
98 this.mSingletonStartMethod = targetStartMethod;
99 }
100 }
101
102
103 public String getTargetStopMethod()
104 {
105 return this.mSingletonStopMethod;
106 }
107
108 public void setTargetStopMethod(String targetStopMethod)
109 throws InvalidParameterException
110 {
111 if (targetStopMethod != null)
112 {
113 this.mSingletonStopMethod = targetStopMethod;
114 }
115 }
116
117 public String getTargetStartMethodArgument()
118 {
119 return this.mSingletonStartMethodArgument ;
120 }
121
122 public void setTargetStartMethodArgument(String targetStartMethodArgument)
123 {
124 this.mSingletonStartMethodArgument = targetStartMethodArgument;
125 }
126
127 public String getTargetStopMethodArgument()
128 {
129 return this.mSingletonStopMethodArgument ;
130 }
131
132 public void setTargetStopMethodArgument(String targetStopMethodArgument)
133 {
134 this.mSingletonStopMethodArgument = targetStopMethodArgument;
135 }
136
137 // HASingleton implementation ------------------------------------
138
139 /**
140 * Call the target start method
141 *
142 * @see org.jboss.ha.singleton.HASingletonSupport#startSingleton()
143 */
144 @Override
145 public void startSingleton()
146 {
147 super.startSingleton();
148
149 try
150 {
151 if (this.mSingleton != null)
152 {
153 this.invokeSingletonMethod( this.mSingleton, this.mSingletonStartMethod, this.mSingletonStartMethodArgument);
154 }
155 else if (this.mSingletonMBean != null)
156 {
157 this.invokeSingletonMBeanMethod( this.mSingletonMBean, this.mSingletonStartMethod, this.mSingletonStartMethodArgument);
158 }
159 else
160 {
161 this.log.warn("No singleton configured; cannot start");
162 }
163 }
164 catch (Exception e)
165 {
166 this.log.error("Controlled Singleton failed to become master", e);
167 }
168 }
169
170 /**
171 * Call the target stop method
172 *
173 * @see org.jboss.ha.singleton.HASingletonSupport#stopSingleton()
174 */
175 @Override
176 public void stopSingleton()
177 {
178 super.stopSingleton();
179
180 try
181 {
182 if (this.mSingleton != null)
183 {
184 this.invokeSingletonMethod( this.mSingleton, this.mSingletonStopMethod, this.mSingletonStopMethodArgument);
185 }
186 else if (this.mSingletonMBean != null)
187 {
188 this.invokeSingletonMBeanMethod( this.mSingletonMBean, this.mSingletonStopMethod, this.mSingletonStopMethodArgument);
189 }
190 else
191 {
192 this.log.warn("No singleton configured; cannot start");
193 }
194 }
195 catch (Exception e)
196 {
197 this.log.error("Controlled Singleton failed to resign from master position", e);
198 }
199 }
200
201 // Protected -----------------------------------------------------
202
203 protected Object invokeSingletonMethod(Object target,
204 String operationName, Object param)
205 throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
206 {
207 if (target != null && operationName != null)
208 {
209 Object[] params;
210 Class<?>[] types;
211
212 if (param != null)
213 {
214 params = new Object[] { param };
215 types = new Class[] { param.getClass() };
216
217 this.log.debug("Calling operation: " + operationName + "(" + param + "), on target: '" + target + "'");
218 }
219 else
220 {
221 params = NO_ARGS;
222 types = NO_TYPES;
223
224 this.log.debug("Calling operation: " + operationName + "(), on target: '" + target + "'");
225 }
226
227 Method method = getTargetMethod(target, operationName, types);
228
229 return method.invoke(target, params);
230 }
231
232 this.log.debug("No configured target mbean or operation to call");
233
234 return null;
235 }
236
237 protected Object invokeSingletonMBeanMethod(ObjectName target,
238 String operationName, Object param)
239 throws InstanceNotFoundException, MBeanException, ReflectionException
240 {
241 if (target != null && operationName != null)
242 {
243 Object[] params;
244 String[] signature;
245
246 if (param != null)
247 {
248 params = new Object[] { param };
249 signature = new String[] { param.getClass().getName() };
250
251 this.log.debug("Calling operation: " + operationName +
252 "(" + param + "), on target: '" + target + "'");
253 }
254 else
255 {
256 params = NO_ARGS;
257 signature = NO_TYPE_NAMES;
258
259 this.log.debug("Calling operation: " + operationName +
260 "(), on target: '" + target + "'");
261 }
262
263 return this.server.invoke(target, operationName, params, signature);
264 }
265
266 this.log.debug("No configured target mbean or operation to call");
267
268 return null;
269 }
270
271 public static Method getTargetMethod(Object target, String methodName, Class<?>[] types)
272 throws NoSuchMethodException
273 {
274 Class<?> clazz = target.getClass();
275 NoSuchMethodException nsme = null;
276 while (clazz != null)
277 {
278 try
279 {
280 Method method = clazz.getDeclaredMethod(methodName, types);
281 return method;
282 }
283 catch (NoSuchMethodException e)
284 {
285 // Cache the one from the top level class
286 if (nsme == null)
287 {
288 nsme = e;
289 }
290 // Keep searching
291 clazz = clazz.getSuperclass();
292 }
293 }
294 throw nsme;
295 }
296 }