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 }