View Javadoc

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 }