1 /**
2 * Copyright Terracotta, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18 package net.sf.ehcache;
19
20
21 import net.sf.ehcache.config.CacheConfiguration;
22 import net.sf.ehcache.pool.sizeof.annotations.IgnoreSizeOf;
23 import net.sf.ehcache.util.TimeUtil;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.NotSerializableException;
29 import java.io.ObjectInputStream;
30 import java.io.ObjectOutputStream;
31 import java.io.Serializable;
32 import java.util.concurrent.atomic.AtomicLongFieldUpdater;
33
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 /**
38 * A Cache Element, consisting of a key, value and attributes.
39 * <p/>
40 * From ehcache-1.2, Elements can have keys and values that are Serializable or Objects. To preserve backward
41 * compatibility, special accessor methods for Object keys and values are provided: {@link #getObjectKey()} and
42 * {@link #getObjectValue()}. If placing Objects in ehcache, developers must use the new getObject... methods to
43 * avoid CacheExceptions. The get... methods are reserved for Serializable keys and values.
44 *
45 * @author Greg Luck
46 * @version $Id: Element.java 6224 2012-09-04 14:13:29Z cdennis $
47 */
48 public class Element implements Serializable, Cloneable {
49
50 /**
51 * serial version
52 * Updated for version 1.2, 1.2.1 and 1.7
53 */
54 private static final long serialVersionUID = 1098572221246444544L;
55
56 private static final Logger LOG = LoggerFactory.getLogger(Element.class.getName());
57
58 private static final AtomicLongFieldUpdater<Element> HIT_COUNT_UPDATER = AtomicLongFieldUpdater.newUpdater(Element.class, "hitCount");
59
60 private static final boolean ELEMENT_VERSION_AUTO = Boolean.getBoolean("net.sf.ehcache.element.version.auto");
61
62 private static final long NOT_SET_ID = 0;
63
64 static {
65 if (ELEMENT_VERSION_AUTO) {
66 LOG.warn("Note that net.sf.ehcache.element.version.auto is set and user provided version will not be honored");
67 }
68 }
69
70 /**
71 * the cache key.
72 */
73 @IgnoreSizeOf
74 private final Object key;
75
76 /**
77 * the value.
78 */
79 private final Object value;
80
81 /**
82 * version of the element. System.currentTimeMillis() is used to compute version for updated elements. That
83 * way, the actual version of the updated element does not need to be checked.
84 */
85 private volatile long version;
86
87 /**
88 * The number of times the element was hit.
89 */
90 private volatile long hitCount;
91
92 /**
93 * The amount of time for the element to live, in seconds. 0 indicates unlimited.
94 */
95 private volatile int timeToLive = Integer.MIN_VALUE;
96
97 /**
98 * The amount of time for the element to idle, in seconds. 0 indicates unlimited.
99 */
100 private volatile int timeToIdle = Integer.MIN_VALUE;
101
102 /**
103 * Pluggable element eviction data instance
104 */
105 private transient volatile ElementEvictionData elementEvictionData;
106
107 /**
108 * If there is an Element in the Cache and it is replaced with a new Element for the same key,
109 * then both the version number and lastUpdateTime should be updated to reflect that. The creation time
110 * will be the creation time of the new Element, not the original one, so that TTL concepts still work.
111 */
112 private volatile long lastUpdateTime;
113
114 private volatile boolean cacheDefaultLifespan = true;
115
116 private volatile long id = NOT_SET_ID;
117
118 /**
119 * A full constructor.
120 * <p/>
121 * Creation time is set to the current time. Last Access Time is not set.
122 *
123 * @since .4
124 */
125 public Element(final Serializable key, final Serializable value, final long version) {
126 this((Object) key, (Object) value, version);
127
128 }
129
130 /**
131 * A full constructor.
132 * <p/>
133 * Creation time is set to the current time. Last Access Time and Previous To Last Access Time
134 * are not set.
135 *
136 * @since 1.2
137 */
138 public Element(final Object key, final Object value, final long version) {
139 this.key = key;
140 this.value = value;
141 this.version = version;
142 HIT_COUNT_UPDATER.set(this, 0);
143 this.elementEvictionData = new DefaultElementEvictionData(System.currentTimeMillis());
144 }
145
146 /**
147 * Constructor.
148 *
149 * @deprecated The {@code nextToLastAccessTime} field is unused since
150 * version 1.7, setting it will have no effect. Use
151 * #Element(Object, Object, long, long, long, long, long)
152 * instead
153 * @since 1.3
154 * @see #Element(Object, Object, long, long, long, long, long)
155 */
156 @Deprecated
157 public Element(final Object key, final Object value, final long version,
158 final long creationTime, final long lastAccessTime, final long nextToLastAccessTime,
159 final long lastUpdateTime, final long hitCount) {
160 this(key, value, version, creationTime, lastAccessTime, lastUpdateTime, hitCount);
161 }
162
163 /**
164 * Constructor.
165 *
166 * @since 1.7
167 */
168 public Element(final Object key, final Object value, final long version,
169 final long creationTime, final long lastAccessTime,
170 final long lastUpdateTime, final long hitCount) {
171 this.key = key;
172 this.value = value;
173 this.version = version;
174 this.lastUpdateTime = lastUpdateTime;
175 HIT_COUNT_UPDATER.set(this, hitCount);
176 this.elementEvictionData = new DefaultElementEvictionData(creationTime, lastAccessTime);
177 }
178
179 /**
180 * Constructor used by ElementData. Needs to be public since ElementData might be in another classloader
181 *
182 * @since 1.7
183 */
184 public Element(final Object key, final Object value, final long version, final long creationTime,
185 final long lastAccessTime, final long hitCount, final boolean cacheDefaultLifespan,
186 final int timeToLive, final int timeToIdle, final long lastUpdateTime) {
187 this.key = key;
188 this.value = value;
189 this.version = version;
190 HIT_COUNT_UPDATER.set(this, hitCount);
191 this.cacheDefaultLifespan = cacheDefaultLifespan;
192 this.timeToLive = timeToLive;
193 this.timeToIdle = timeToIdle;
194 this.lastUpdateTime = lastUpdateTime;
195 this.elementEvictionData = new DefaultElementEvictionData(creationTime, lastAccessTime);
196 }
197
198 /**
199 * Constructor used by ehcache-server
200 *
201 * @param key any non null value
202 * @param value any value, including nulls
203 * @param eternal specify as non-null to override cache configuration
204 * @param timeToIdleSeconds specify as non-null to override cache configuration
205 * @param timeToLiveSeconds specify as non-null to override cache configuration
206 */
207 public Element(final Object key, final Object value,
208 final Boolean eternal, final Integer timeToIdleSeconds, final Integer timeToLiveSeconds) {
209 this.key = key;
210 this.value = value;
211 if (eternal != null) {
212 setEternal(eternal.booleanValue());
213 }
214 if (timeToIdleSeconds != null) {
215 setTimeToIdle(timeToIdleSeconds.intValue());
216 }
217 if (timeToLiveSeconds != null) {
218 setTimeToLive(timeToLiveSeconds.intValue());
219 }
220 this.elementEvictionData = new DefaultElementEvictionData(System.currentTimeMillis());
221 }
222
223 /**
224 * Constructor.
225 *
226 * @param key
227 * @param value
228 */
229 public Element(final Serializable key, final Serializable value) {
230 this((Object) key, (Object) value, 1L);
231 }
232
233 /**
234 * Constructor.
235 *
236 * @param key
237 * @param value
238 * @since 1.2
239 */
240 public Element(final Object key, final Object value) {
241 this(key, value, 1L);
242 }
243
244 /**
245 * Gets the key attribute of the Element object.
246 *
247 * @return The key value.
248 * @throws CacheException if the key is not {@code Serializable}.
249 * @deprecated Please use {@link #getObjectKey()} instead.
250 */
251 @Deprecated
252 public final Serializable getKey() throws CacheException {
253 try {
254 return (Serializable) getObjectKey();
255 } catch (ClassCastException e) {
256 throw new CacheException("The key " + getObjectKey() + " is not Serializable. Consider using Element.getObjectKey()");
257 }
258 }
259
260 /**
261 * Gets the key attribute of the Element object.
262 * <p/>
263 * This method is provided for those wishing to use ehcache as a memory only cache
264 * and enables retrieval of non-Serializable values from elements.
265 *
266 * @return The key as an Object. i.e no restriction is placed on it
267 * @see #getKey()
268 */
269 public final Object getObjectKey() {
270 return key;
271 }
272
273 /**
274 * Gets the value attribute of the Element object.
275 *
276 * @return The value which must be {@code Serializable}. If not use {@link #getObjectValue}.
277 * @throws CacheException if the value is not {@code Serializable}.
278 * @deprecated Please use {@link #getObjectValue()} instead.
279 */
280 @Deprecated
281 public final Serializable getValue() throws CacheException {
282 try {
283 return (Serializable) getObjectValue();
284 } catch (ClassCastException e) {
285 throw new CacheException("The value " + getObjectValue() + " for key " + getObjectKey() +
286 " is not Serializable. Consider using Element.getObjectValue()");
287 }
288 }
289
290 /**
291 * Gets the value attribute of the Element object as an Object.
292 * <p/>
293 * This method is provided for those wishing to use ehcache as a memory only cache
294 * and enables retrieval of non-Serializable values from elements.
295 *
296 * @return The value as an Object. i.e no restriction is placed on it
297 * @see #getValue()
298 * @since 1.2
299 */
300 public final Object getObjectValue() {
301 return value;
302 }
303
304 /**
305 * Equals comparison with another element, based on the key.
306 */
307 @Override
308 public final boolean equals(final Object object) {
309 if (object == null || !(object instanceof Element)) {
310 return false;
311 }
312
313 Element element = (Element) object;
314 if (key == null || element.getObjectKey() == null) {
315 return false;
316 }
317
318 return key.equals(element.getObjectKey());
319 }
320
321 /**
322 * Sets time to Live
323 *
324 * @param timeToLiveSeconds the number of seconds to live
325 */
326 public void setTimeToLive(final int timeToLiveSeconds) {
327 if (timeToLiveSeconds < 0) {
328 throw new IllegalArgumentException("timeToLive can't be negative");
329 }
330 this.cacheDefaultLifespan = false;
331 this.timeToLive = timeToLiveSeconds;
332 }
333
334 /**
335 * Sets time to idle
336 *
337 * @param timeToIdleSeconds the number of seconds to idle
338 */
339 public void setTimeToIdle(final int timeToIdleSeconds) {
340 if (timeToIdleSeconds < 0) {
341 throw new IllegalArgumentException("timeToIdle can't be negative");
342 }
343 this.cacheDefaultLifespan = false;
344 this.timeToIdle = timeToIdleSeconds;
345 }
346
347 /**
348 * Gets the hashcode, based on the key.
349 */
350 @Override
351 public final int hashCode() {
352 return key.hashCode();
353 }
354
355 /**
356 * Sets the version attribute of the ElementAttributes object.
357 *
358 * @param version The new version value
359 */
360 public final void setVersion(final long version) {
361 this.version = version;
362 }
363
364 /**
365 * Sets the element identifier (this field is used internally by ehcache). Setting this field in application code will not be preserved
366 *
367 * @param id The new id value
368 */
369 void setId(final long id) {
370 if (id == NOT_SET_ID) {
371 throw new IllegalArgumentException("Id cannot be set to " + id);
372 }
373 this.id = id;
374 }
375
376 /**
377 * Gets the element identifier (this field is used internally by ehcache)
378 *
379 * @return id the id
380 */
381 long getId() {
382 final long v = id;
383 if (v == NOT_SET_ID) {
384 throw new IllegalStateException("Id not set");
385 }
386 return v;
387 }
388
389 /**
390 * Determines if an Id has been set on this element
391 *
392 * @return true if this element has an Id
393 */
394 boolean hasId() {
395 return id != NOT_SET_ID;
396 }
397
398 /**
399 * Sets the creationTime attribute of the ElementAttributes object.
400 * <p>
401 * Note that in a Terracotta clustered environment, resetting the creation
402 * time will not have any effect.
403 *
404 * @deprecated Resetting the creation time is not recommended as of version
405 * 1.7
406 */
407 @Deprecated
408 public final void setCreateTime() {
409 this.elementEvictionData.setCreationTime(System.currentTimeMillis());
410 }
411
412 /**
413 * Gets the creationTime of the Element
414 *
415 * @return The creationTime value
416 */
417 public final long getCreationTime() {
418 return elementEvictionData.getCreationTime();
419 }
420
421 /**
422 * Calculates the latest of creation and update time
423 * @return if never updated, creation time is returned, otherwise updated time
424 */
425 public final long getLatestOfCreationAndUpdateTime() {
426 if (0 == lastUpdateTime) {
427 return elementEvictionData.getCreationTime();
428 } else {
429 return lastUpdateTime;
430 }
431 }
432
433 /**
434 * Gets the version attribute of the ElementAttributes object.
435 *
436 * @return The version value
437 */
438 public final long getVersion() {
439 return version;
440 }
441
442 /**
443 * Gets the last access time.
444 * Access means a get. So a newly created {@link Element}
445 * will have a last access time equal to its create time.
446 */
447 public final long getLastAccessTime() {
448 return elementEvictionData.getLastAccessTime();
449 }
450
451 /**
452 * Gets the next to last access time.
453 *
454 * @deprecated The {@code nextToLastAccessTime} field is unused since
455 * version 1.7, retrieving it will return the {@code
456 * lastAccessTime}. Use #getLastAccessTime() instead.
457 * @see #getLastAccessTime()
458 */
459 @Deprecated
460 public final long getNextToLastAccessTime() {
461 return getLastAccessTime();
462 }
463
464 /**
465 * Gets the hit count on this element.
466 */
467 public final long getHitCount() {
468 return hitCount;
469 }
470
471 /**
472 * Retrieves this element's eviction data instance.
473 *
474 * @return this element's eviction data instance
475 */
476 public ElementEvictionData getElementEvictionData() {
477 return elementEvictionData;
478 }
479
480 /**
481 * Sets this element's eviction data instance.
482 *
483 * @param elementEvictionData this element's eviction data
484 */
485 public void setElementEvictionData(ElementEvictionData elementEvictionData) {
486 this.elementEvictionData = elementEvictionData;
487 }
488
489 /**
490 * Resets the hit count to 0 and the last access time to now. Used when an Element is put into a cache.
491 */
492 public final void resetAccessStatistics() {
493 elementEvictionData.resetLastAccessTime(this);
494 HIT_COUNT_UPDATER.set(this, 0);
495 }
496
497 /**
498 * Sets the last access time to now and increase the hit count.
499 */
500 public final void updateAccessStatistics() {
501 elementEvictionData.updateLastAccessTime(System.currentTimeMillis(), this);
502 HIT_COUNT_UPDATER.incrementAndGet(this);
503 }
504
505 /**
506 * Sets the last access time to now without updating the hit count.
507 */
508 public final void updateUpdateStatistics() {
509 lastUpdateTime = System.currentTimeMillis();
510 if (ELEMENT_VERSION_AUTO) {
511 version = lastUpdateTime;
512 }
513 }
514
515
516 /**
517 * Returns a {@link String} representation of the {@link Element}.
518 */
519 @Override
520 public final String toString() {
521 StringBuilder sb = new StringBuilder();
522
523 sb.append("[ key = ").append(key)
524 .append(", value=").append(value)
525 .append(", version=").append(version)
526 .append(", hitCount=").append(hitCount)
527 .append(", CreationTime = ").append(this.getCreationTime())
528 .append(", LastAccessTime = ").append(this.getLastAccessTime())
529 .append(" ]");
530
531 return sb.toString();
532 }
533
534 /**
535 * Clones an Element. A completely new object is created, with no common references with the
536 * existing one.
537 * <p/>
538 * This method will not work unless the Object is Serializable
539 * <p/>
540 * Warning: This can be very slow on large object graphs. If you use this method
541 * you should write a performance test to verify suitability.
542 *
543 * @return a new {@link Element}, with exactly the same field values as the one it was cloned from.
544 * @throws CloneNotSupportedException
545 */
546 @Override
547 public final Object clone() throws CloneNotSupportedException {
548 //Not used. Just to get code inspectors to shut up
549 super.clone();
550
551 try {
552 Element element = new Element(deepCopy(key), deepCopy(value), version);
553 element.elementEvictionData = elementEvictionData.clone();
554 HIT_COUNT_UPDATER.set(element, hitCount);
555 return element;
556 } catch (IOException e) {
557 LOG.error("Error cloning Element with key " + key
558 + " during serialization and deserialization of value");
559 throw new CloneNotSupportedException();
560 } catch (ClassNotFoundException e) {
561 LOG.error("Error cloning Element with key " + key
562 + " during serialization and deserialization of value");
563 throw new CloneNotSupportedException();
564 }
565 }
566
567 private static Object deepCopy(final Object oldValue) throws IOException, ClassNotFoundException {
568 Serializable newValue = null;
569 ByteArrayOutputStream bout = new ByteArrayOutputStream();
570 ObjectOutputStream oos = null;
571 ObjectInputStream ois = null;
572 try {
573 oos = new ObjectOutputStream(bout);
574 oos.writeObject(oldValue);
575 ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
576 ois = new ObjectInputStream(bin);
577 newValue = (Serializable) ois.readObject();
578 } finally {
579 try {
580 if (oos != null) {
581 oos.close();
582 }
583 if (ois != null) {
584 ois.close();
585 }
586 } catch (Exception e) {
587 LOG.error("Error closing Stream");
588 }
589 }
590 return newValue;
591 }
592
593 /**
594 * The size of this object in serialized form. This is not the same
595 * thing as the memory size, which is JVM dependent. Relative values should be meaningful,
596 * however.
597 * <p/>
598 * Warning: This method can be <b>very slow</b> for values which contain large object graphs.
599 * <p/>
600 * If the key or value of the Element is not Serializable, an error will be logged and 0 will be returned.
601 *
602 * @return The serialized size in bytes
603 */
604 public final long getSerializedSize() {
605
606 if (!isSerializable()) {
607 return 0;
608 }
609 long size = 0;
610 ByteArrayOutputStream bout = new ByteArrayOutputStream();
611 ObjectOutputStream oos = null;
612 try {
613 oos = new ObjectOutputStream(bout);
614 oos.writeObject(this);
615 size = bout.size();
616 return size;
617 } catch (IOException e) {
618 LOG.debug("Error measuring element size for element with key " + key + ". Cause was: " + e.getMessage());
619 } finally {
620 try {
621 if (oos != null) {
622 oos.close();
623 }
624 } catch (Exception e) {
625 LOG.error("Error closing ObjectOutputStream");
626 }
627 }
628
629 return size;
630 }
631
632 /**
633 * Whether the element may be Serialized.
634 * <p/>
635 * While Element implements Serializable, it is possible to create non Serializable elements
636 * for use in MemoryStores. This method checks that an instance of Element really is Serializable
637 * and will not throw a NonSerializableException if Serialized.
638 * <p/>
639 * This method was tweaked in 1.6 as it has been shown that Serializable classes can be serializaed as can
640 * null, regardless of what class it is a null of. ObjectOutputStream.write(null) works and ObjectInputStream.read()
641 * will read null back.
642 *
643 * @return true if the element is Serializable
644 * @since 1.2
645 */
646 public final boolean isSerializable() {
647 return isKeySerializable()
648 && (value instanceof Serializable || value == null)
649 && elementEvictionData.canParticipateInSerialization();
650 }
651
652 /**
653 * Whether the element's key may be Serialized.
654 * <p/>
655 * While Element implements Serializable, it is possible to create non Serializable elements and/or
656 * non Serializable keys for use in MemoryStores.
657 * <p/>
658 * This method checks that an instance of an Element's key really is Serializable
659 * and will not throw a NonSerializableException if Serialized.
660 *
661 * @return true if the element's key is Serializable
662 * @since 1.2
663 */
664 public final boolean isKeySerializable() {
665 return key instanceof Serializable || key == null;
666 }
667
668 /**
669 * If there is an Element in the Cache and it is replaced with a new Element for the same key,
670 * then both the version number and lastUpdateTime should be updated to reflect that. The creation time
671 * will be the creation time of the new Element, not the original one, so that TTL concepts still work.
672 *
673 * @return the time when the last update occured. If this is the original Element, the time will be null
674 */
675 public long getLastUpdateTime() {
676 return lastUpdateTime;
677 }
678
679 /**
680 * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past.
681 *
682 * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is
683 * considered not able to expire.
684 * @see #getExpirationTime()
685 */
686 public boolean isExpired() {
687 if (!isLifespanSet() || isEternal()) {
688 return false;
689 }
690
691 long now = System.currentTimeMillis();
692 long expirationTime = getExpirationTime();
693
694 return now > expirationTime;
695 }
696
697 /**
698 * An element is expired if the expiration time as given by {@link #getExpirationTime()} is in the past.
699 * <p>
700 * This method in addition propogates the default TTI/TTL values of the supplied cache into this element.
701 *
702 * @param config config to take default parameters from
703 * @return true if the Element is expired, otherwise false. If no lifespan has been set for the Element it is
704 * considered not able to expire.
705 * @see #getExpirationTime()
706 */
707 public boolean isExpired(CacheConfiguration config) {
708 if (cacheDefaultLifespan) {
709 if (config.isEternal()) {
710 timeToIdle = 0;
711 timeToLive = 0;
712 } else {
713 timeToIdle = TimeUtil.convertTimeToInt(config.getTimeToIdleSeconds());
714 timeToLive = TimeUtil.convertTimeToInt(config.getTimeToLiveSeconds());
715 }
716 }
717 return isExpired();
718 }
719
720 /**
721 * Returns the expiration time based on time to live. If this element also has a time to idle setting, the expiry
722 * time will vary depending on whether the element is accessed.
723 *
724 * @return the time to expiration
725 */
726 public long getExpirationTime() {
727 if (!isLifespanSet() || isEternal()) {
728 return Long.MAX_VALUE;
729 }
730
731 long expirationTime = 0;
732 long ttlExpiry = elementEvictionData.getCreationTime() + TimeUtil.toMillis(getTimeToLive());
733
734 long mostRecentTime = Math.max(elementEvictionData.getCreationTime(), elementEvictionData.getLastAccessTime());
735 long ttiExpiry = mostRecentTime + TimeUtil.toMillis(getTimeToIdle());
736
737 if (getTimeToLive() != 0 && (getTimeToIdle() == 0 || elementEvictionData.getLastAccessTime() == 0)) {
738 expirationTime = ttlExpiry;
739 } else if (getTimeToLive() == 0) {
740 expirationTime = ttiExpiry;
741 } else {
742 expirationTime = Math.min(ttlExpiry, ttiExpiry);
743 }
744 return expirationTime;
745 }
746
747 /**
748 * @return true if the element is eternal
749 */
750 public boolean isEternal() {
751 return (0 == timeToIdle) && (0 == timeToLive);
752 }
753
754 /**
755 * Sets whether the element is eternal.
756 *
757 * @param eternal
758 */
759 public void setEternal(final boolean eternal) {
760 if (eternal) {
761 this.cacheDefaultLifespan = false;
762 this.timeToIdle = 0;
763 this.timeToLive = 0;
764 } else if (isEternal()) {
765 this.cacheDefaultLifespan = false;
766 this.timeToIdle = Integer.MIN_VALUE;
767 this.timeToLive = Integer.MIN_VALUE;
768 }
769 }
770
771 /**
772 * Whether any combination of eternal, TTL or TTI has been set.
773 *
774 * @return true if set.
775 */
776 public boolean isLifespanSet() {
777 return this.timeToIdle != Integer.MIN_VALUE || this.timeToLive != Integer.MIN_VALUE;
778 }
779
780 /**
781 * @return the time to live, in seconds
782 */
783 public int getTimeToLive() {
784 if (Integer.MIN_VALUE == timeToLive) {
785 return 0;
786 } else {
787 return timeToLive;
788 }
789 }
790
791 /**
792 * @return the time to idle, in seconds
793 */
794 public int getTimeToIdle() {
795 if (Integer.MIN_VALUE == timeToIdle) {
796 return 0;
797 } else {
798 return timeToIdle;
799 }
800 }
801
802 /**
803 * @return <code>false</code> if this Element has a custom lifespan
804 */
805 public boolean usesCacheDefaultLifespan() {
806 return cacheDefaultLifespan;
807 }
808
809 /**
810 * Set the default parameters of this element - those from its enclosing cache.
811 * @param tti TTI in seconds
812 * @param ttl TTL in seconds
813 * @param eternal <code>true</code> if the element is eternal.
814 */
815 protected void setLifespanDefaults(int tti, int ttl, boolean eternal) {
816 if (eternal) {
817 this.timeToIdle = 0;
818 this.timeToLive = 0;
819 } else if (isEternal()) {
820 this.timeToIdle = Integer.MIN_VALUE;
821 this.timeToLive = Integer.MIN_VALUE;
822 } else {
823 timeToIdle = tti;
824 timeToLive = ttl;
825 }
826 }
827
828 /**
829 * Custom serialization write logic
830 */
831 private void writeObject(ObjectOutputStream out) throws IOException {
832 if (!elementEvictionData.canParticipateInSerialization()) {
833 throw new NotSerializableException();
834 }
835 out.defaultWriteObject();
836 out.writeInt(TimeUtil.toSecs(elementEvictionData.getCreationTime()));
837 out.writeInt(TimeUtil.toSecs(elementEvictionData.getLastAccessTime()));
838 }
839
840 /**
841 * Custom serialization read logic
842 */
843 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
844 in.defaultReadObject();
845 elementEvictionData = new DefaultElementEvictionData(TimeUtil.toMillis(in.readInt()), TimeUtil.toMillis(in.readInt()));
846 }
847 }
848