001/* 002 * Copyright (c) 2003-2010 The Regents of the University of California. 003 * All rights reserved. 004 * 005 * '$Author: welker $' 006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 007 * '$Revision: 24234 $' 008 * 009 * Permission is hereby granted, without written agreement and without 010 * license or royalty fees, to use, copy, modify, and distribute this 011 * software and its documentation for any purpose, provided that the above 012 * copyright notice and the following two paragraphs appear in all copies 013 * of this software. 014 * 015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 019 * SUCH DAMAGE. 020 * 021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 026 * ENHANCEMENTS, OR MODIFICATIONS. 027 * 028 */ 029 030package org.kepler.objectmanager.cache; 031 032import java.io.BufferedInputStream; 033import java.io.File; 034import java.io.FileInputStream; 035import java.io.IOException; 036import java.io.InputStream; 037import java.io.ObjectInputStream; 038import java.io.Serializable; 039import java.util.Date; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Vector; 043 044import org.apache.commons.logging.Log; 045import org.apache.commons.logging.LogFactory; 046 047/** 048 * Represents an item in the cache 049 */ 050public abstract class DataCacheObject extends CacheObject implements Runnable, 051 Serializable { 052 /** 053 * Description of the Field 054 */ 055 protected final static int CACHE_BUSY = 1; 056 /** 057 * Description of the Field 058 */ 059 protected final static int CACHE_ERROR = 2; 060 /** 061 * Description of the Field 062 */ 063 protected final static int CACHE_COMPLETE = 3; 064 /** 065 * Description of the Field 066 */ 067 protected final static int CACHE_EMPTY = 4; 068 069 /** 070 * Description of the Field 071 */ 072 private transient Thread mThread = null; 073 074 /** 075 * Description of the Field 076 */ 077 private static Log log; 078 private static boolean isDebugging; 079 080 static { 081 log = LogFactory 082 .getLog("org.kepler.objectmanager.cache.DataCacheObject"); 083 isDebugging = log.isDebugEnabled(); 084 } 085 086 private final static String cachedatapath = CacheManager.cachePath 087 + File.separator + "cachedata" + File.separator; 088 089 /** 090 * Description of the Field 091 */ 092 private Date mCreatedDate = new Date(); 093 /** 094 * Description of the Field 095 */ 096 private String mResourceName = null; 097 /** 098 * Absolute filename of data file. 099 */ 100 private String mLocalFileName = null; 101 102 /** 103 * Description of the Field 104 */ 105 private transient Vector mListeners = new Vector(); 106 107 /** 108 * Description of the Field 109 */ 110 private int mStatus = CACHE_EMPTY; 111 112 /** 113 * Constructor 114 */ 115 public DataCacheObject() { 116 } 117 118 /** 119 *@param createdDate 120 * The mCreatedDate to set. 121 */ 122 public final void setCreatedDate(Date createdDate) { 123 mCreatedDate = createdDate; 124 } 125 126 /** 127 *@param localFileName 128 * The mLocalFileName to set. 129 */ 130 public final void setAbsoluteFileName(String localFileName) { 131 mLocalFileName = localFileName; 132 } 133 134 /** 135 *@param localFileName 136 * The mLocalFileName to set. 137 */ 138 public final void setBaseFileName(String localFileName) { 139 mLocalFileName = cachedatapath + localFileName; 140 } 141 142 /** 143 *@param resourceName 144 * The mResourceName to set. 145 */ 146 public final void setResourceName(String resourceName) { 147 mResourceName = resourceName; 148 } 149 150 /** 151 * 152 */ 153 public final Object getObject() { 154 return new File(mLocalFileName); 155 } 156 157 public final File getFile() { 158 return (File) getObject(); 159 } 160 161 /** 162 * Return the data as an InputStream. The data is read from the cached file 163 * on disk, so this method assumes the cache item has already been 164 * retrieved. If not, or if there is an error, then the return value will be 165 * null. 166 * 167 *@return InputStream representing the data 168 */ 169 public final InputStream getDataInputStream() { 170 BufferedInputStream bis = null; 171 172 if (mLocalFileName != null && mLocalFileName.length() > 0) { 173 try { 174 File file = getFile(); 175 176 if (file != null && file.exists()) { 177 FileInputStream fis = new FileInputStream(file); 178 179 if (fis != null) { 180 bis = new BufferedInputStream(fis); 181 } 182 } 183 } catch (Exception e) { 184 System.err.println(e); 185 } 186 } else { 187 log.debug("loadData - mLocalFileName was null: \n " + super.getName() 188 + " \n" + mResourceName + " \n" + mLocalFileName); 189 } 190 return bis; 191 } 192 193 /** 194 * Returns whether it is in empty state 195 * 196 * */ 197 public final boolean isEmpty() { 198 return mStatus == CACHE_EMPTY; 199 } 200 201 /** 202 * Return the status of getting the data 203 * 204 * 205 * */ 206 public final boolean isReady() { 207 return mStatus == CACHE_COMPLETE; 208 } 209 210 /** 211 * Returns whether it is busy getting the data 212 * 213 * */ 214 public final boolean isBusy() { 215 return mStatus == CACHE_BUSY; 216 } 217 218 /** 219 * Returns whether it is in error state 220 * 221 * */ 222 public final boolean isError() { 223 return mStatus == CACHE_ERROR; 224 } 225 226 /** 227 *@return Returns the mCreatedDate. 228 */ 229 public final Date getCreatedDate() { 230 return mCreatedDate; 231 } 232 233 /** 234 *@return Returns the mLocalFileName. 235 */ 236 public final String getAbsoluteFileName() { 237 return mLocalFileName; 238 } 239 240 /** 241 *@return Returns the mLocalFileName. 242 */ 243 public final String getBaseFileName() { 244 int inx = mLocalFileName.lastIndexOf(File.separator); 245 246 if (inx > -1) { 247 return mLocalFileName.substring(inx + 1); 248 } 249 return mLocalFileName; 250 } 251 252 /** 253 *@return Returns the mResourceName. 254 */ 255 public final String getResourceName() { 256 return mResourceName; 257 } 258 259 /** 260 *@return Returns the mStatus. 261 */ 262 protected final int getStatus() { 263 return mStatus; 264 } 265 266 /** 267 * Add a listenero 268 * 269 *@param aListener 270 * the listener to add 271 */ 272 public final void addListener(DataCacheListener aListener) { 273 // If the listener is null, don't do anything. 274 if (aListener == null) { 275 return; 276 } 277 // If the object is already finished, then just notify. 278 if (isReady() || isError()) { 279 notifyOne(aListener); 280 return; 281 } 282 // Otherwise, we need to add the listener to the list 283 synchronized (mListeners) { 284 mListeners.addElement(aListener); 285 } 286 } 287 288 /** 289 * Removes a listener 290 * 291 *@param aListener 292 * the listener to remove 293 */ 294 public final void removeListener(DataCacheListener aListener) { 295 if (aListener == null) { 296 return; 297 } 298 synchronized (mListeners) { 299 mListeners.removeElement(aListener); 300 } 301 } 302 303 /** 304 * Removes all the listeners 305 */ 306 public final void removeAllListeners() { 307 synchronized (mListeners) { 308 mListeners.clear(); 309 } 310 } 311 312 /** 313 * Notifies the listener that the "getting" of the data has completed 314 */ 315 public final void notifyListeners() { 316 List localcopy; 317 synchronized (mListeners) { 318 localcopy = (List) mListeners.clone(); 319 } 320 for (Iterator i = localcopy.iterator(); i.hasNext();) { 321 DataCacheListener l = (DataCacheListener) i.next(); 322 notifyOne(l); 323 } 324 } 325 326 private final void notifyOne(DataCacheListener l) { 327 l.complete(this); 328 } 329 330 /** 331 * Refreshes the data from the original source 332 * 333 *@param aListener 334 */ 335 public final void refresh(DataCacheListener aListener) { 336 clear(); 337 // System.err.println("Refresh Name "+mName + 338 // "has new file name"+mLocalFileName); 339 addListener(aListener); 340 mCreatedDate = new Date(); 341 start(); 342 } 343 344 /** 345 * Description of the Method 346 */ 347 public final void reset() { 348 clear(); 349 mStatus = CACHE_EMPTY; 350 mLocalFileName = null; 351 } 352 353 /** 354 * Clear the dat from this cache item 355 */ 356 public final void clear() { 357 if (mLocalFileName != null && mLocalFileName.length() > 0) { 358 File file = new File(mLocalFileName); 359 360 if (file != null && file.exists()) { 361 file.delete(); 362 } 363 } 364 removeAllListeners(); 365 } 366 367 /** 368 * Abstract method for actually getting the data while in the thread 369 * 370 * @return return the new status. 371 */ 372 public abstract int doWork(); 373 374 /** 375 * return a string representation of this datacacheobject 376 */ 377 public String toString() { 378 StringBuffer sb = new StringBuffer(); 379 sb.append("{"); 380 sb.append("classname = " + getClass().getName() + "\n"); 381 sb.append("name = " + super._name + "\n"); 382 // sb.append("resname = " + (mCreatedDate != null ? 383 // mCreatedDate.getTime() : 0) + "\n"); 384 sb.append("resname = " + mResourceName + "\n"); 385 sb.append("date = " 386 + (mCreatedDate != null ? mCreatedDate.getTime() : 0) + "\n"); 387 sb.append("fileName = " + mLocalFileName + "\n"); 388 sb.append("}"); 389 return sb.toString(); 390 } 391 392 // ---------------------------------------------------------------- 393 // -- Runnable Interface 394 // ---------------------------------------------------------------- 395 /** 396 * Description of the Method 397 */ 398 public void start() { 399 if (mThread == null) { 400 mThread = new Thread(this); 401 mThread.setPriority(Thread.MIN_PRIORITY); 402 mThread.setName(super._name); 403 mThread.start(); 404 } 405 } 406 407 public void stop() { 408 if (mThread != null) { 409 mThread.interrupt(); 410 } 411 } 412 413 /** 414 */ 415 public void run() { 416 if (!isReady()) { 417 mStatus = CACHE_BUSY; 418 419 if (mThread.isInterrupted()) { 420 mStatus = CACHE_ERROR; 421 } else { 422 mStatus = doWork(); 423 } 424 } 425 if (mThread.isInterrupted()) { 426 mStatus = CACHE_ERROR; 427 } 428 429 log.debug("run - Done With Work."); 430 notifyListeners(); 431 432 try { 433 CacheManager.getInstance().updateObject(this); 434 } catch (CacheException e) { 435 log.error("CacheException occurred during run", e); 436 } 437 mThread = null; 438 } 439 440 /** 441 * Custom deserialization method. Need to initialize mListeners to empty 442 * vector. 443 * 444 * @param ois 445 * @throws IOException 446 * @throws ClassNotFoundException 447 */ 448 private void readObject(ObjectInputStream ois) throws IOException, 449 ClassNotFoundException { 450 ois.defaultReadObject(); 451 mListeners = new Vector(); 452 } 453 454}