1 /* Open Source Java Caching Service 2 * Copyright (C) 2002 Frank Karlstrøm 3 * This library is free software; you can redistribute it and/or 4 * modify it under the terms of the GNU Lesser General Public 5 * License as published by the Free Software Foundation; either 6 * version 2.1 of the License, or (at your option) any later version. 7 * 8 * This library is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * Lesser General Public License for more details. 12 * 13 * You should have received a copy of the GNU Lesser General Public 14 * License along with this library; if not, write to the Free Software 15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 16 * 17 * The author can be contacted by email: fjankk@sourceforge.net 18 */ 19 package org.fjank.jcache; 20 21 import java.io.Serializable; 22 23 import javax.util.jcache.Attributes; 24 import javax.util.jcache.CacheEventListener; 25 import javax.util.jcache.CacheLoader; 26 import javax.util.jcache.InvalidArgumentException; 27 28 /** 29 * This class defines the attributes an object in the cache can have. 30 */ 31 public final class AttributesImpl implements Cloneable, Serializable, Attributes { 32 private static final int ONE_DAY = 24; 33 private static final int ONE_HOUR = 60; 34 private static final int ONE_MINUTE = 60; 35 /** the time the associated CacheObject was created. */ 36 private long createTime = System.currentTimeMillis(); 37 /** the default time the associated CacheObject should live in the cache */ 38 private long defaultTTL = -1; 39 /** 40 * Is used to specify wich attributes should be set in the attributes 41 * object. The differnet attributes wich is valid is defined as public 42 * static variables in the {@link Attributes}class. 43 */ 44 private long flags; 45 /** the time the associated CacheObject should be idle in the cache */ 46 private long idleTime; 47 /** the CacheListener for the associated CacheObject */ 48 private transient CacheEventListener listener; 49 /** the CacheLoader for the associated CacheObject */ 50 private transient CacheLoader loader; 51 /** the size for the associated CacheObject */ 52 private int size; 53 /** the time the associated CacheObject should be live the cache */ 54 private long timeToLive = -1; 55 /** the version of the associated CacheObject */ 56 private long version; 57 58 /** 59 * Creates new Attributes 60 */ 61 public AttributesImpl() { 62 } 63 64 public AttributesImpl(Attributes attributes) { 65 this.defaultTTL = attributes.getDefaultTimeToLive(); 66 this.idleTime = attributes.getIdleTime(); 67 68 this.listener = attributes.getListener(); 69 this.loader = attributes.getLoader(); 70 this.size = attributes.getSize(); 71 this.timeToLive = attributes.getTimeToLive(); 72 this.version = attributes.getVersion(); 73 long flags = 0; 74 75 if (attributes.isSet(Attributes.DISTRIBUTE)) { 76 flags |= Attributes.DISTRIBUTE; 77 } 78 if (attributes.isSet(Attributes.NOFLUSH)) { 79 flags |= Attributes.NOFLUSH; 80 } 81 if (attributes.isSet(Attributes.REPLY)) { 82 flags |= Attributes.REPLY; 83 } 84 if (attributes.isSet(Attributes.SYNCHRONIZE)) { 85 flags |= Attributes.SYNCHRONIZE; 86 } 87 if (attributes.isSet(Attributes.SPOOL)) { 88 flags |= Attributes.SPOOL; 89 } 90 if (attributes.isSet(Attributes.GROUP_TTL_DESTROY)) { 91 flags |= Attributes.GROUP_TTL_DESTROY; 92 } 93 if (attributes.isSet(Attributes.ORIGINAL)) { 94 flags |= Attributes.ORIGINAL; 95 } 96 this.flags = flags; 97 } 98 99 public void applyAttributes(Attributes attributes) { 100 this.idleTime = attributes.getIdleTime(); 101 this.timeToLive = attributes.getTimeToLive(); 102 this.defaultTTL = attributes.getDefaultTimeToLive(); 103 CacheEventListener listener = attributes.getListener(); 104 setListener(Attributes.INVALIDATE_EVENT, listener); 105 } 106 107 public boolean equals(Object arg0) { 108 if (arg0 instanceof AttributesImpl) { 109 AttributesImpl obj = (AttributesImpl) arg0; 110 if (defaultTTL != obj.defaultTTL) 111 return false; 112 if (flags != obj.flags) 113 return false; 114 if (listener != obj.listener) 115 return false; 116 if (loader != obj.loader) 117 return false; 118 if (size != obj.size) 119 return false; 120 if (timeToLive != obj.timeToLive) 121 return false; 122 if (version != obj.version) 123 return false; 124 return true; 125 } 126 return super.equals(arg0); 127 } 128 129 /** 130 * returns the time the object was loaded into the cache. The time is the 131 * number of milliseconds since midnight, January 1, 1970 (UTC). 132 * 133 * @return the time the object was loaded into the cache. The time is the 134 * number of milliseconds since midnight, January 1, 1970 (UTC). 135 */ 136 public long getCreateTime() { 137 return createTime; 138 } 139 140 public long getDefaultTimeToLive() { 141 return defaultTTL; 142 } 143 144 /** 145 * returns the current value for the idle time interval. 146 * 147 * @return the current value for the idle time interval. 148 */ 149 public long getIdleTime() { 150 return idleTime; 151 } 152 153 /** 154 * Gets the CacheEventListener. 155 * 156 * @author Philippe Fajeau 157 * @return The CacheEventListener. 158 */ 159 public CacheEventListener getListener() { 160 return listener; 161 } 162 163 /** 164 * returns the {@link CacheLoader}attribute. 165 * 166 * @return the {@link CacheLoader}attribute. 167 */ 168 public CacheLoader getLoader() { 169 return loader; 170 } 171 172 /** 173 * returns the size of the object. this size is set by the 174 * {@link #setSize(int)} method, or in the case of StreamAccess objects, the 175 * size is calculated by the cache. 176 * 177 * @todo create and implement an online size calculator. 178 * @return the size of the object, or 0 if the size has not been set. 179 */ 180 public int getSize() { 181 return size; 182 } 183 184 /** 185 * returns the current value for the time to live interval. 186 * 187 * @return the current value for the time to live interval. 188 */ 189 public long getTimeToLive() { 190 if (defaultTTL != -1 && timeToLive == -1) { 191 return defaultTTL; 192 } 193 return timeToLive; 194 } 195 196 /** 197 * returns the current value of version. 198 * 199 * @return the current value of version. 200 */ 201 public long getVersion() { 202 return version; 203 } 204 205 /** 206 * Checks wether the flags are set or not. 207 * 208 * @param theFlags 209 * the flags to be checked. may be OR-ed together, for wich this 210 * method will return true only if all flags are set. 211 * 212 * @return true if the specified attribute is set, false otherwise. 213 */ 214 public boolean isSet(final long theFlags) { 215 return ((this.flags | theFlags) ^ this.flags) == 0; 216 } 217 218 /** 219 * resets the Attributes to its default values. The attributes wich are 220 * reset are expiration time attributes, time to live, default time to live, 221 * idle time and event handlers. 222 * 223 * @todo This method should be package private, thus this class should be 224 * moved to org.fjank.jcache, an interface should be extracted, and 225 * that should be public, and in this package. 226 */ 227 public void reset() { 228 AttributesImpl def = new AttributesImpl(); 229 this.idleTime = def.idleTime; 230 this.timeToLive = def.timeToLive; 231 this.defaultTTL = def.defaultTTL; 232 this.listener = def.listener; 233 } 234 235 /** 236 * Sets the createTime. 237 * 238 * @param aCreateTime 239 * The createTime to set 240 */ 241 public void setCreateTime(final long aCreateTime) { 242 if (aCreateTime < 0) { 243 return; 244 } 245 this.createTime = aCreateTime; 246 } 247 248 /** 249 * Will set the maximum time the associated cache object will stay in the 250 * cache before it is invalidated. For regions and groups, this will 251 * establish a default time to live that is applied individually to each 252 * member in the group or region. It will not cause the entire group or 253 * region to time out as a whole. For individual objects, the default time 254 * to live is equivalent with time to live. If both are set the default time 255 * to live is ignored. The time starts when the object is loaded into the 256 * cache(by the {@link CacheLoader}objector put by the 257 * {@link CacheAccess#replace(Object, Object)}) or when the time to live 258 * attribute is set by the 259 * {@link CacheLoader#setAttributes(Object,Attributes)} method. 260 * 261 * @param ttl 262 * the time to live in seconds. The 263 * {@link #timeToSeconds(int, int, int, int)} can be used to 264 * convert days, hours, minutes to secounds. 265 * 266 * @throws InvalidArgumentException 267 * if a negative value for ttl is supplied. 268 */ 269 public void setDefaultTimeToLive(final long ttl) throws InvalidArgumentException { 270 if (ttl < 0) { 271 throw new InvalidArgumentException("Default time to live must be a positive number."); 272 } 273 this.defaultTTL = ttl; 274 } 275 276 /** 277 * Is used to specify wich attributes should be set in the attributes 278 * object. The different attributes wich is valid is defined as public 279 * static variables in the {@link Attributes}class. 280 * 281 * @param theFlags 282 * The attributes to set. the attributes may be OR-ed together. 283 * I.e. Attributes.DISTRIBUTE | Attributes.SYNCHRONIZE Invalid 284 * flags are silently ignored. To reset all flags you use 0 as a 285 * parameter. I.e. setFlags(0) 286 */ 287 public void setFlags(final long theFlags) { 288 if (theFlags < 0) { 289 return; 290 } 291 this.flags = theFlags; 292 } 293 294 /** 295 * sets the maximum time the associated cache object will remain in the 296 * cache without being referenced before it is invalidated. 297 * 298 * @param idle 299 * is in seconds. The {@link #timeToSeconds(int, int, int,int)} 300 * can be used to convert days, hours, minutes to secounds. 301 * 302 * @throws InvalidArgumentException 303 * if a negative value for idle is supplied. 304 */ 305 public void setIdleTime(final long idle) throws InvalidArgumentException { 306 if (idle < 0) { 307 throw new InvalidArgumentException("Idle time must be a positive number."); 308 } 309 this.idleTime = idle; 310 } 311 312 /** 313 * Register an event listener object to be executed when the specified event 314 * occurs with relationship to the associated object. Currently the only 315 * invalidate event being monitored is Attributes.INVALIDATE_EVENT. If 316 * invalid parameters are passed such as invalid events, or null as 317 * listener, this method silently returns without doing any changes to this 318 * object. 319 * 320 * @param event 321 * The event to listen for. 322 * @param aListener 323 * the listener to fire when the event occurs. 324 * 325 *@todo Should these Attributes only have one Listener, or should several 326 * be supported? 327 */ 328 public void setListener(final int event, final CacheEventListener aListener) { 329 if ((event == INVALIDATE_EVENT) && (aListener != null)) { 330 this.listener = aListener; 331 } 332 } 333 334 /** 335 * Will associate a loader object with this object. 336 * 337 * @param aLoader 338 * The loader to set. This parameter can be null. 339 */ 340 public void setLoader(final CacheLoader aLoader) { 341 this.loader = aLoader; 342 } 343 344 /** 345 * Is used to specify the size in bytes of the object being cached. This is 346 * used to determine when the cache capacity is reached. If the cache is not 347 * using object size to determine the capacity (It can also use object 348 * counts) this value is ignored. 349 * 350 * @param aSize 351 * the size to be set. if this parameter is smaller than zero, 352 * this method silently returns. 353 */ 354 public void setSize(final int aSize) { 355 if (aSize < 0) { 356 return; 357 } 358 this.size = aSize; 359 } 360 361 /** 362 * Will set the maximum time the associated cache object will stay in the 363 * cache before it is invalidated. The time starts when the object is loaded 364 * into the cache(by the {@link CacheLoader}object or put by the 365 * {@link CacheAccess#replace(Object, Object)}) or when the time to live 366 * attribute is set by the 367 * {@link CacheLoader#setAttributes(Object, Attributes)} method. 368 * 369 * @param ttl 370 * the time to live in seconds. The 371 * {@link #timeToSeconds(int, int, int, int)} can be used to 372 * convert days, hours, minutes to seconds. 373 * 374 * @throws InvalidArgumentException 375 * if a negative value for ttl is supplied. 376 */ 377 public void setTimeToLive(final long ttl) throws InvalidArgumentException { 378 if (ttl < 0) { 379 throw new InvalidArgumentException("Time to live must be a positive number."); 380 } 381 this.timeToLive = ttl; 382 } 383 384 /** 385 * Sets the version attribute. Is only maintained for user convenience. It 386 * is not used internally by the cache. 387 * 388 * @param aVersion 389 * the version number to set. 390 */ 391 public void setVersion(final long aVersion) { 392 this.version = aVersion; 393 } 394 395 /** 396 * Will convert the time specified into seconds. 397 * 398 * @param days 399 * number of days. 400 * @param hours 401 * number of hours. 402 * @param minutes 403 * number of minutes. 404 * @param seconds 405 * number of seconds. 406 * 407 * @return the converted time in seconds. 408 * 409 * @throws InvalidArgumentException 410 * if any of the parameters are negative values. 411 */ 412 public long timeToSeconds(final int days, final int hours, final int minutes, final int seconds) throws InvalidArgumentException { 413 if (days < 0) { 414 throw new InvalidArgumentException("Days must be larger than zero."); 415 } 416 if (hours < 0) { 417 throw new InvalidArgumentException("Hours must be larger than zero."); 418 } 419 if (minutes < 0) { 420 throw new InvalidArgumentException("Minutes must be larger than zero."); 421 } 422 if (seconds < 0) { 423 throw new InvalidArgumentException("Seconds must be larger than zero."); 424 } 425 return seconds + (ONE_MINUTE * minutes) + (ONE_MINUTE * ONE_HOUR * hours) + (ONE_MINUTE * ONE_HOUR * ONE_DAY * days); 426 } 427 428 /** 429 * returns these Attributes as a String. 430 * 431 * @return these Attributes as a String. 432 */ 433 public String toString() { 434 return "Attributes {ttl:" + timeToLive + '}'; //$NON-NLS-1$ 435 } 436 }