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.io.IOException;
19 import java.util.Timer;
20 import java.util.TimerTask;
21 import java.util.logging.Level;
22 import java.util.logging.Logger;
23
24 import org.ov4j.data.ClassComparable;
25 import org.ov4j.data.Version;
26
27 /**
28 * This is the background thread which will cache results.
29 *
30 * @author smolloy
31 *
32 */
33 public class DelayedCacher implements Runnable {
34 /**
35 * Logger for this class
36 */
37 private static final Logger logger = Logger.getLogger(DelayedCacher.class.getName());
38
39 /** Thread performing the calls. */
40 private final MethodCaller theCaller;
41
42 /** The result to be cached. */
43 private Version<ClassComparable> theVersion;
44
45 /** The timeout period after which the call is considered to have failed. */
46 private final long theTimeout;
47
48 /** The ID to use for storing the result. */
49 private final CachedResultId theId;
50
51 /** The CacheHandler. */
52 private final CacheHandler theCache;
53
54 /** Whether the ID should be added or simply committed. */
55 private boolean addBeforeCommit = false;
56
57 /** Whether or not the call has timed out. */
58 private boolean timedout = false;
59
60 /** Task which will set the timeout flag after the timeout period. */
61 protected TimerTask theTimer = new TimerTask() {
62 @Override
63 public void run() {
64 setTimedout(true);
65 }
66 };
67
68 /**
69 * Constructor.
70 *
71 * @param theCaller
72 * The thread making the call.
73 * @param theVersion
74 * The result to cache.
75 * @param theTimeout
76 * The timeout period.
77 * @param theId
78 * The ID to use for storing the result.
79 * @param theCache
80 * The CacheHandler.
81 * @param addBeforeCommit
82 * Whether or not the ID should be added as well as the result committed.
83 */
84 public DelayedCacher(final MethodCaller theCaller, final Version<ClassComparable> theVersion,
85 final long theTimeout, final CachedResultId theId, final CacheHandler theCache, final boolean addBeforeCommit) {
86 this.theCaller = theCaller;
87 this.theVersion = theVersion;
88 this.theTimeout = theTimeout;
89 this.theId = theId;
90 this.theCache = theCache;
91 this.addBeforeCommit = addBeforeCommit;
92 }
93
94 /**
95 * @return Returns the result.
96 */
97 public Version<ClassComparable> getTheVersion() {
98 return theVersion;
99 }
100
101 /**
102 * @return Returns the timedout.
103 */
104 public boolean hasTimedout() {
105 return timedout;
106 }
107
108 /**
109 * Perform caching. Will try sleeping until the method caller is done, then will cache the result.
110 */
111 public void run() {
112 if (DelayedCacher.logger.isLoggable(Level.FINER)) {
113 DelayedCacher.logger.entering("DelayedCacher", "run()", "start");
114 }
115
116 final Timer timer = new Timer();
117 timer.schedule(theTimer, theTimeout);
118 do {
119 try {
120 Thread.sleep(theTimeout / 4);
121 } catch (final InterruptedException e) {
122 if (DelayedCacher.logger.isLoggable(Level.FINE)) {
123 DelayedCacher.logger.logp(Level.FINE, "DelayedCacher", "run()", "exception ignored", e);
124 }
125 }
126 } while (!timedout && !theCaller.hasFailed() && theCaller.getTheResult() == null);
127
128 timer.cancel();
129 final Object res = theCaller.getTheResult();
130 if (res != null) {
131 ClassComparable theObject = null;
132 if (res instanceof ClassComparable) {
133 theObject = (ClassComparable) res;
134 } else {
135 theObject = new ClassComparable();
136 theObject.setTheObject(res);
137 }
138 if (theObject != null) {
139 try {
140 if (theVersion == null) {
141 theVersion = new Version<ClassComparable>();
142 theVersion.setAuthor(CacheHandler.CACHE_AUTHOR);
143 theVersion.setVersionNumber(0);
144 theVersion.setComment(CacheHandler.NORMAL_COMMENT);
145 addBeforeCommit = true;
146 }
147 theVersion.setVersionedObject(theObject);
148 if (addBeforeCommit) {
149 theCache.addNCommit(theId, theVersion);
150 } else {
151 theCache.commit(theId, theVersion);
152 }
153 } catch (final IOException e) {
154 if (DelayedCacher.logger.isLoggable(Level.FINE)) {
155 DelayedCacher.logger.logp(Level.FINE, "DelayedCacher", "run()", "exception ignored", e);
156 }
157 } catch (final InstantiationException e) {
158 if (DelayedCacher.logger.isLoggable(Level.FINE)) {
159 DelayedCacher.logger.logp(Level.FINE, "DelayedCacher", "run()", "exception ignored", e);
160 }
161 } catch (final IllegalAccessException e) {
162 if (DelayedCacher.logger.isLoggable(Level.FINE)) {
163 DelayedCacher.logger.logp(Level.FINE, "DelayedCacher", "run()", "exception ignored", e);
164 }
165 } catch (final ClassNotFoundException e) {
166 if (DelayedCacher.logger.isLoggable(Level.FINE)) {
167 DelayedCacher.logger.logp(Level.FINE, "DelayedCacher", "run()", "exception ignored", e);
168 }
169 }
170 }
171 }
172
173 if (DelayedCacher.logger.isLoggable(Level.FINER)) {
174 DelayedCacher.logger.exiting("DelayedCacher", "run()", "end");
175 }
176 }
177
178 /**
179 * @param timedout
180 * The timedout to set.
181 */
182 public void setTimedout(final boolean timedout) {
183 this.timedout = timedout;
184 }
185 }