1 /**
2 * Copyright 2005 Steve Molloy
3 *
4 * This file is part of OV4J.
5 *
6 * OV4J is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
8 *
9 * OV4J is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with OV4J; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14 *
15 */
16 package org.ov4j.cache;
17
18 import java.lang.reflect.Method;
19 import java.util.Timer;
20 import java.util.TimerTask;
21 import java.util.logging.Level;
22 import java.util.logging.Logger;
23
24 /**
25 * This class performs the method calls.
26 *
27 * @author smolloy
28 *
29 */
30 public class MethodCaller {
31 /**
32 * Logger for this class
33 */
34 private static final Logger logger = Logger.getLogger(MethodCaller.class.getName());
35
36 /** Method to call. */
37 private final Method theMethod;
38
39 /** Object on which to call the method. */
40 private final Object theObj;
41
42 /** Arguments to pass to the method. */
43 private Object[] theArgs;
44
45 /** result of the call. */
46 private Object theResult;
47
48 /** Flag to indicate if the call has timedout. */
49 private boolean timedout = false;
50
51 /** Exception caught while calling the method. */
52 private Exception error;
53
54 /** Thread doing the call. */
55 private final Runnable theCaller = new Runnable() {
56 public void run() {
57 invokeMethod();
58 }
59 };
60
61 /** Task setting timeout flag after the timeout period. */
62 protected TimerTask theTimer = new TimerTask() {
63 @Override
64 public void run() {
65 setTimedout(true);
66 }
67 };
68
69 /**
70 * Constructor.
71 *
72 * @param theMethod
73 * The method to call.
74 * @param theObj
75 * The object on which to call it.
76 * @param theArgs
77 * The arguments to pass to the method call.
78 */
79 public MethodCaller(final Method theMethod, final Object theObj, final Object... theArgs) {
80 this.theMethod = theMethod;
81 this.theObj = theObj;
82 if (theArgs == null) {
83 this.theArgs = null;
84 } else {
85 this.theArgs = new Object[theArgs.length];
86 System.arraycopy(theArgs, 0, this.theArgs, 0, theArgs.length);
87 }
88 }
89
90 /**
91 * Start the threads to perform the call.
92 *
93 * @param timeout
94 * Timeout period.
95 */
96 public void call(final long timeout) {
97 if (MethodCaller.logger.isLoggable(Level.FINER)) {
98 MethodCaller.logger.entering("MethodCaller", "call(long=" + timeout + ")", "start");
99 }
100
101 final Timer timer = new Timer();
102 final Thread t = new Thread(theCaller);
103 timer.schedule(theTimer, timeout);
104 t.start();
105 while (!timedout && error == null && theResult == null) {
106 try {
107 Thread.sleep(1000);
108 } catch (final InterruptedException e) {
109 if (MethodCaller.logger.isLoggable(Level.FINE)) {
110 MethodCaller.logger.logp(Level.FINE, "MethodCaller", "call(long=" + timeout + ")",
111 "exception ignored", e);
112 }
113 }
114 }
115 timer.cancel();
116
117 if (MethodCaller.logger.isLoggable(Level.FINER)) {
118 MethodCaller.logger.exiting("MethodCaller", "call(long=" + timeout + ")", "end");
119 }
120 }
121
122 /**
123 * @return Returns the error.
124 */
125 public Exception getError() {
126 return error;
127 }
128
129 /**
130 * @return Returns the theResult.
131 */
132 public Object getTheResult() {
133 return theResult;
134 }
135
136 /**
137 * @return Returns true if an error occured while trying to call the method.
138 */
139 public boolean hasFailed() {
140 return (error != null);
141 }
142
143 /**
144 * @return Returns the timedout.
145 */
146 public boolean hasTimedout() {
147 return timedout;
148 }
149
150 /**
151 * Invoke the method.
152 *
153 */
154 public void invokeMethod() {
155 if (MethodCaller.logger.isLoggable(Level.FINER)) {
156 MethodCaller.logger.entering("MethodCaller", "invokeMethod()", "start");
157 }
158
159 try {
160 theResult = theMethod.invoke(theObj, theArgs);
161 } catch (final Exception e) {
162 if (MethodCaller.logger.isLoggable(Level.FINE)) {
163 MethodCaller.logger.logp(Level.FINE, "MethodCaller", "invokeMethod()", "Exception caught", e);
164 }
165
166 error = e;
167 }
168
169 if (MethodCaller.logger.isLoggable(Level.FINER)) {
170 MethodCaller.logger.exiting("MethodCaller", "invokeMethod()", "end");
171 }
172 }
173
174 /**
175 * @param timedout
176 * The timedout to set.
177 */
178 public void setTimedout(final boolean timedout) {
179 this.timedout = timedout;
180 }
181 }